/*
 * Copyright (C) 2012 Realtek Semiconductor Corp.
 * All Rights Reserved.
 *
 * This program is the proprietary software of Realtek Semiconductor
 * Corporation and/or its licensors, and only be used, duplicated,
 * modified or distributed under the authorized license from Realtek.
 *
 * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
 * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
 *
 * $Revision: 39101 $
 * $Date: 2013-06-24 04:35:27 -0500 (Fri, 03 May 2013) $
 *
 * Purpose : OMCI driver layer module defination
 *
 * Feature : The file includes the following modules and sub-modules
 *           (1) OMCI (G.984.4)
 *
 */


/****************************************************************/
/* Include Files                                                */
/****************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/kfifo.h>

#include <linux/sched.h>
#include <linux/slab.h>
#include <pkt_redirect/pkt_redirect.h>
#include <DRV/platform/include/rt_fc/omci_pf_rt_fc.h>

/*rt api*/
#include <rtk/rt/rt_gpon.h>
#include <rtk/rt/rt_stat.h>
#include <rtk/rt/rt_rate.h>
#include <rtk/rt/rt_port.h>
#include <rtk/rt/rt_switch.h>
#include <rtk/rt/rt_time.h>
#include <rt_stat_ext.h>



/*rtk api internal use*/
#include <rtk/pon_led.h>

#include "omci_dm_cb.h"
#include "hal/phy/phydef.h"
#include <module/intr_bcaster/intr_bcaster.h>
#include "hal/common/halctrl.h"

#include <DRV/platform/include/rt_fc/omci_drv_ext.h>
#include <DRV/platform/include/rt_fc/omci_pf_qos_flow.h>
//#include "omci_drv_ext.h"


#include <DRV/omci_drv_mic.h>


/****************************************************************/
/* Symbol Definition                                            */
/****************************************************************/
#define TCONT_ALLOC_ID_984_987_RESERVED		(0xFFFF)
#define OMCI_DEFAULT_CTAG_TPID 0x8100
#define OMCI_DEFAULT_STAG_TPID 0x88A8

#define TRANSCEIVER_MAX_LEN     (24)
#define TRANSCEIVER_A0_ADDR     (0x50)
#define TRANSCEIVER_A2_ADDR     (0x51)
#define TRANSCEIVER_I2C_PORT    (0)

#define DS_DFT_CONNECTION_ID    (0xffffff)

/****************************************************************/
/* Type Definition                                              */
/****************************************************************/

typedef struct {
	unsigned int                connectionId;
	struct list_head	        list;
} omci_connection_info_t;



/****************************************************************/
/* Macro Declaration                                            */
/****************************************************************/

#define TO_CONNECTION_ID(_serverId, _entryId)  ((((_entryId) & 0xfff) << 24 ) | (_serverId& 0xffffff))
#define CONNECTION_ID_TO_SERVER_ID(_conn_idx)   (((_conn_idx) >> 0 )&0xffffff)


/****************************************************************/
/* Data Declaration                                             */
/****************************************************************/
static unsigned char omci_ik[OMCI_IK_LEN]   = {0};

static pf_db_t gPlatformDb;
static omci_dmm_cb_t *pDmmCb = NULL;

static struct list_head    gL2FlowHead,gVeipFlowHead,gL2DsDftHead,gVeipDsDftHead;

static uint8 g_omci_dying_gasp_msg[] = {
0x00, 0x00, 0x10, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00};

static uint8 g_omci_dying_gasp_msg_len = 0;

/****************************************************************/
/* Function Declaration                                         */
/****************************************************************/
static int _InitTcontDb(void)
{
    unsigned int i;

    for(i=0;i<gPlatformDb.maxTcont;i++)
    {
        gPlatformDb.tCont[i].allocId = TCONT_ALLOC_ID_984_987_RESERVED;
    }
    return 0;
}


static int _SetTcontDb(unsigned int tcontId, unsigned int allocId)
{
    if(tcontId >= gPlatformDb.maxTcont)
    {
        return OMCI_ERR_FAILED;
    }


    gPlatformDb.tCont[tcontId].allocId = allocId;
    
    return OMCI_ERR_OK;
}

static int _DumpTcontCfg(uint32 maxTcont)
{
    unsigned int tcontId;
    unsigned int allocId;

    printk("\r\n");
    printk("[Dump T-CONT config]\r\n");
    printk("TCONT  Alloc-ID\r\n");
    printk("---------------\r\n");
   
    for(tcontId=0;tcontId<maxTcont;tcontId++)
    {

        if(RT_ERR_OK == rt_gpon_tcont_get(tcontId, &allocId))
        {
            printk("%-5d  %-8d\r\n",tcontId, allocId);
        }
    }

    return OMCI_ERR_OK;
}



static int _DumpUsGemFlowCfg(uint32 maxUsGemFlow)
{
    unsigned int i;
    rt_gpon_usFlow_t usFlowCfg;

    printk("\r\n");
    printk("[Dump US GEM flow config]\r\n");
    printk("Flow ID | GEM Port | TCont | TC-Queue | AES\r\n");
    printk("-------------------------------------------\r\n");

   
    for(i=0;i<maxUsGemFlow;i++)
    {

        if(RT_ERR_OK == rt_gpon_usFlow_get(i, &usFlowCfg))
    {
            printk("%-8d  %-9d  %-8d %-8d  %-8d\r\n",i, usFlowCfg.gemPortId, 
                usFlowCfg.tcontId, usFlowCfg.tcQueueId, usFlowCfg.aesEn);
        }
    }

    return OMCI_ERR_OK;
}

static int _DumpDsGemFlowCfg(uint32 maxUsGemFlow)
{
    unsigned int i;
    rt_gpon_dsFlow_t dsFlowCfg;
    
    printk("\r\n");
    printk("[Dump DS GEM flow config]\r\n");
    printk("Flow ID | GEM Port | AES\r\n");
    printk("-------------------------\r\n");
    
    for(i=0;i<maxUsGemFlow;i++)
    {

        if(RT_ERR_OK == rt_gpon_dsFlow_get(i, &dsFlowCfg))
    {
            printk("%-8d  %-9d  %-8d\r\n",i, dsFlowCfg.gemPortId, dsFlowCfg.aesEn);
        }
    }

    return OMCI_ERR_OK;
}


static int _DumpTcontQueueCfg(uint32 maxTcont, uint32 maxTcQueue)
{
    unsigned int tcId,tcQid;
    rt_gpon_queueCfg_t qCfg;

    printk("\r\n");
    printk("[Dump T-CONT queue config]\r\n");
    printk("T-CONT  | TC-Queue | CIR     | PIR     | SchType | Weight\r\n");
    printk("---------------------------------------------------------\r\n");
    
    for(tcId=0;tcId<maxTcont;tcId++)
    {
        for(tcQid=0;tcQid<maxTcQueue;tcQid++)
        {
            if(RT_ERR_OK == rt_gpon_ponQueue_get(tcId, tcQid, &qCfg))
            {
                printk("%-8d  %-9d  %-8d  %-8d  %-8d  %-8d\r\n",
                    tcId, tcQid, qCfg.cir, qCfg.pir, qCfg.scheduleType, qCfg.weight);
            }
        }
    }

    return OMCI_ERR_OK;
}



static int _DelAllTcont(void)
{
    unsigned int i;
    
    for(i=0;i<gPlatformDb.maxTcont;i++)
    {
        if(gPlatformDb.tCont[i].allocId != TCONT_ALLOC_ID_984_987_RESERVED)
        {
            if(OMCI_ERR_OK == rt_gpon_tcont_del(i))
                gPlatformDb.tCont[i].allocId = TCONT_ALLOC_ID_984_987_RESERVED;
            else
               OMCI_LOG(OMCI_LOG_LEVEL_ERR,"delete tcont fail allocId %d",gPlatformDb.tCont[i].allocId); 
        }
    }
    return 0;
}


static void omci_send_to_user(rtk_gpon_pkt_t* omci)
{
    int ret;
    
    if((ret = pkt_redirect_kernelApp_sendPkt(PR_USER_UID_GPONOMCI,1, sizeof(rtk_gpon_pkt_t), (unsigned char *)omci))!=RT_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_WARN,"%s() ret:%d",__FUNCTION__,ret);
    }
    return;
}


static void omci_send_to_nic(unsigned short len,unsigned char *ptr) /*follow ca_ni_send_packet of ca_ni_tx.c*/
{

    rtk_gpon_omci_msg_t *pkt_ptr = (rtk_gpon_omci_msg_t *)ptr;
    uint8_t *omci_ptr = pkt_ptr->msg;
    uint32_t omci_len = pkt_ptr->len;
    
    if(len != sizeof(rtk_gpon_omci_msg_t))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : tx wrong length Error!!",__FUNCTION__,__LINE__);
        return;
    }
    
    OMCI_LOG(OMCI_LOG_LEVEL_DBG,"======%s %d : TX OMCI len %u ======",__FUNCTION__,__LINE__,omci_len);
    OMCI_LOG(OMCI_LOG_LEVEL_DBG,"%s %d : TX OMCI content",__FUNCTION__,__LINE__);
    if (gDrvCtrl.logLevel >= OMCI_LOG_LEVEL_DBG)
        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, omci_ptr, omci_len, true);

    if (RT_ERR_OK != rt_gpon_omci_tx(omci_len, omci_ptr))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : TX OMCI Error!!",__FUNCTION__,__LINE__);
    }

    return;
}

static uint32 omci_rx_callback(uint32 msgLen,uint8 *pMsg)
{
    rtk_gpon_pkt_t pkt;

    OMCI_LOG(OMCI_LOG_LEVEL_DBG,"======%s %d : OMCI RX  len %u ======",__FUNCTION__,__LINE__, msgLen);


    OMCI_LOG(OMCI_LOG_LEVEL_DBG,"%s %d : RX OMCI content",__FUNCTION__,__LINE__);
    if (gDrvCtrl.logLevel >= OMCI_LOG_LEVEL_DBG)
        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, pMsg, msgLen, true);

    memset(&pkt,0,sizeof(rtk_gpon_pkt_t));
    pkt.type = RTK_GPON_MSG_OMCI;
    memcpy(&pkt.msg.omci.msg,pMsg,msgLen);
    pkt.msg.omci.len = msgLen;

    omci_send_to_user(&pkt);

    return 0;


}


static int pf_rt_SetOmciDyingGaspMsg(omci_dying_gasp_msg_t *pOmciMsg)
{
    if(NULL == pOmciMsg)
        return OMCI_ERR_PARAM; 

    if(pOmciMsg->len > OMCI_DYING_MSG_MAX_LEN)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : len=%d, error!!", __FUNCTION__, __LINE__, pOmciMsg->len);
        return OMCI_ERR_PARAM;        
    }

    g_omci_dying_gasp_msg_len = pOmciMsg->len;
    memcpy(&g_omci_dying_gasp_msg[0], &pOmciMsg->content[0], pOmciMsg->len);

    if (gDrvCtrl.logLevel >= OMCI_LOG_LEVEL_DBG)
        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, &g_omci_dying_gasp_msg[0], g_omci_dying_gasp_msg_len, true);

   return OMCI_ERR_OK; 

}

 void omci_send_dying_gasp(void *cookie)
{
    if(0 == g_omci_dying_gasp_msg_len)
    {
        return;
    }

    printk(KERN_NOTICE "OMCI dg !\n");

    if (RT_ERR_OK != rt_gpon_omci_tx(g_omci_dying_gasp_msg_len, g_omci_dying_gasp_msg))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : TX OMCI Error!!",__FUNCTION__,__LINE__);
    }
}


static int omci_init(void)
{
    int32 ret = OMCI_ERR_OK;

    if((ret = pkt_redirect_kernelApp_reg(PR_KERNEL_UID_GPONOMCI,omci_send_to_nic))!=RT_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"OMCI pkt_redirect_kernelApp_reg Error!!\n");
        return ret;
    }

    if((ret = rt_gpon_omci_rx_callback_register(&omci_rx_callback))!=RT_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"OMCI reg rt gpon rx callback fail ret:%d !!\n", ret);
        return ret;
    }  

    if((ret = rt_intr_isr_callback_register(RT_INTR_TYPE_DYING_GASP, omci_send_dying_gasp))!=RT_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"OMCI reg rt gpon rx callback fail ret:%d !!\n", ret);
        return ret;
    }  

    return ret;
}


static int omci_exit(void)
{
    int32 ret = OMCI_ERR_OK;
    /*remove receive GPON OMCI callback for send packet to NIC*/
    if((ret = pkt_redirect_kernelApp_dereg(PR_KERNEL_UID_GPONOMCI))!=RT_ERR_OK)
    {
        return ret;
    }

    return ret;
}


static int pf_rt_dm_GetOutTpidMap(unsigned int tpid, unsigned int *realTpid)
{
    switch(tpid)
    {
        case TPID_8100:
            *realTpid = 0x8100;
            break;
        case TPID_88A8:
            *realTpid = 0x88A8;
            break;
        case TPID_0800:
            *realTpid = 0x0800;
            break;
        case TPID_9100:
            *realTpid = 0x9100;
            break;
        default:
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d unsupport TPID", __FUNCTION__, __LINE__);
            break;
    }
    return OMCI_ERR_OK;
}



static int pf_rt_dm_GetVidAct(OMCI_VID_ACT_MODE_e vidAct, omci_pon_wan_vlan_vid_action_t *pDmVidAct)
{
    int ret = OMCI_ERR_OK; 
    
    switch (vidAct)
    {
        case VID_ACT_ASSIGN:
            *pDmVidAct = OMCI_PON_WAN_VLAN_VID_ASSIGN;
            break;
        case VID_ACT_COPY_INNER:
            *pDmVidAct = OMCI_PON_WAN_VLAN_VID_COPY_FROM_2ND_TAG;
            break;            
        case VID_ACT_COPY_OUTER:
            *pDmVidAct = OMCI_PON_WAN_VLAN_VID_COPY_FROM_1ST_TAG;
            break; 
        case VID_ACT_TRANSPARENT:
            *pDmVidAct = OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
            break; 
        default:
            ret = OMCI_ERR_FAILED;
            break;

    }
    return ret;

}

static int pf_rt_dm_GetPriAct(OMCI_PRI_ACT_MODE_e priAct, omci_pon_wan_vlan_pri_action_t *pDmPriAct)
{
    int ret = OMCI_ERR_OK;
    
    switch (priAct)
    {
        case PRI_ACT_ASSIGN:
            *pDmPriAct = OMCI_PON_WAN_VLAN_PRI_ASSIGN;
            break;
        case PRI_ACT_COPY_INNER:
            *pDmPriAct = OMCI_PON_WAN_VLAN_PRI_COPY_FROM_2ND_TAG;
            break;            
        case PRI_ACT_COPY_OUTER:
            *pDmPriAct = OMCI_PON_WAN_VLAN_PRI_COPY_FROM_1ST_TAG;
            break; 
        case PRI_ACT_FROM_DSCP:
            *pDmPriAct = OMCI_PON_WAN_VLAN_PRI_COPY_FROM_DSCP_REMAP;
            break; 
        case PRI_ACT_TRANSPARENT:
            *pDmPriAct = OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
            break; 
        default:
            ret = OMCI_ERR_FAILED;
            break;
    }
    return ret;
}


static int pf_rt_dm_GetVlanTagAct(OMCI_VLAN_ACT_ts *pVlanTagAct, omci_pon_wan_vlan_action_t *pDmVlanTagAct,int finalTagNum, int filterTagNum)
{

    if(NULL == pVlanTagAct || NULL == pDmVlanTagAct)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    switch (pVlanTagAct->vlanAct)
    {
        case VLAN_ACT_ADD:
            if(finalTagNum > filterTagNum)
            {
                pDmVlanTagAct->tagAction = OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            }
            else
            {
                pDmVlanTagAct->tagAction = OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            }
            pf_rt_dm_GetVidAct(pVlanTagAct->vidAct, &pDmVlanTagAct->tagVidAction);
            pf_rt_dm_GetPriAct(pVlanTagAct->priAct, &pDmVlanTagAct->tagPriAction);
            break;
        case VLAN_ACT_MODIFY:
            pDmVlanTagAct->tagAction = OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            pf_rt_dm_GetVidAct(pVlanTagAct->vidAct, &pDmVlanTagAct->tagVidAction);
            pf_rt_dm_GetPriAct(pVlanTagAct->priAct, &pDmVlanTagAct->tagPriAction);
            break;
        case VLAN_ACT_REMOVE:
            pDmVlanTagAct->tagAction = OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            pf_rt_dm_GetVidAct(pVlanTagAct->vidAct, &pDmVlanTagAct->tagVidAction);
            pf_rt_dm_GetPriAct(pVlanTagAct->priAct, &pDmVlanTagAct->tagPriAction);
            break;
        case VLAN_ACT_TRANSPARENT:
        case VLAN_ACT_NON:
        default:
            pDmVlanTagAct->tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            break;
    }

    pDmVlanTagAct->assignedVid = pVlanTagAct->assignVlan.vid;
    pDmVlanTagAct->assignedPri = pVlanTagAct->assignVlan.pri;
    pDmVlanTagAct->assignedTpid = pVlanTagAct->assignVlan.tpid;

    return OMCI_ERR_OK;

}

static int 
pf_rt_dm_GetEthertypeFilterRule(OMCI_VLAN_FILTER_MODE_e filterMode,  OMCI_ETHTYPE_FILTER_MODE_e ethertype, omci_dm_filter_rule_t *pDmFilterRule)
{
    if(NULL == pDmFilterRule)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }


    if (filterMode & VLAN_FILTER_ETHTYPE)
    {

        if (ETHTYPE_FILTER_IP == ethertype)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
            pDmFilterRule->etherType = 0x0800;
        }

        if (ETHTYPE_FILTER_PPPOE== ethertype)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
            pDmFilterRule->etherType = 0x8863;
        }


        if (ETHTYPE_FILTER_ARP == ethertype)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
            pDmFilterRule->etherType = 0x0806;
        }

        if (ETHTYPE_FILTER_PPPOE_S== ethertype)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
            pDmFilterRule->etherType = 0x8864;
        }

        if (ETHTYPE_FILTER_IPV6 == ethertype)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
            pDmFilterRule->etherType = 0x86dd;
        }
    }

    return OMCI_ERR_OK;

}


static int 
pf_rt_dm_GetDscpFilterRule(OMCI_VLAN_FILTER_MODE_e filterMode, unsigned char *pDscpMap, omci_dm_filter_rule_t *pDmFilterRule)
{
    if(NULL == pDscpMap || NULL == pDmFilterRule)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }


    if (filterMode & VLAN_FILTER_DSCP_PRI)
    {
        pDmFilterRule->filterMask |= OMCI_DM_FILTER_DSCP_BIT;
        memcpy(&pDmFilterRule->dscp[0], pDscpMap, 8);
        
    }

    return OMCI_ERR_OK;

}




static int 
pf_rt_dm_GetOuterVlanFilterRule(OMCI_VLAN_FILTER_MODE_e filterMode, OMCI_VLAN_ts *pVlanVal, omci_dm_filter_rule_t *pDmFilterRule)
{
    if(NULL == pVlanVal || NULL == pDmFilterRule)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    if (filterMode & VLAN_FILTER_VID)
    {
        pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
        pDmFilterRule->outerTagVid = pVlanVal->vid;
    }

    if (filterMode & VLAN_FILTER_PRI)
    {
        pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
        pDmFilterRule->outerTagPri = pVlanVal->pri;
    }


    if (filterMode & VLAN_FILTER_TCI)
    {
        pDmFilterRule->filterMask |=
            (OMCI_DM_FILTER_OUTER_VID_BIT | OMCI_DM_FILTER_OUTER_PRI_BIT);
        pDmFilterRule->outerTagVid = pVlanVal->vid;
        pDmFilterRule->outerTagPri = pVlanVal->pri;
    }
    return OMCI_ERR_OK;
}


static int 
pf_rt_dm_GetInnerVlanFilterRule(OMCI_VLAN_FILTER_MODE_e filterMode, OMCI_VLAN_ts *pVlanVal, omci_dm_filter_rule_t *pDmFilterRule)
{

    if(NULL == pVlanVal || NULL == pDmFilterRule)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    if (filterMode & VLAN_FILTER_VID)
    {
        pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
        pDmFilterRule->innerTagVid = pVlanVal->vid;
    }

    if (filterMode & VLAN_FILTER_PRI)
    {
        pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
        pDmFilterRule->innerTagPri = pVlanVal->pri;
    }

    if (filterMode & VLAN_FILTER_TCI)
    {
        pDmFilterRule->filterMask |=
            (OMCI_DM_FILTER_INNER_VID_BIT | OMCI_DM_FILTER_INNER_PRI_BIT);
        pDmFilterRule->innerTagVid = pVlanVal->vid;
        pDmFilterRule->innerTagPri = pVlanVal->pri;
    }
    return OMCI_ERR_OK;
}



static int pf_rt_dm_GetFilterRule(OMCI_VLAN_OPER_ts *pVlanRule, omci_dm_filter_rule_t *pDmFilterRule)
{

    if(NULL == pVlanRule || NULL == pDmFilterRule)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }


    /* set filter */
    switch (pVlanRule->filterMode)
    {
        case VLAN_OPER_MODE_FORWARD_ALL:
            break;
        case VLAN_OPER_MODE_FORWARD_UNTAG:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            pDmFilterRule->outerTagIf = 0;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            pDmFilterRule->innerTagIf = 0;
            break;
        case VLAN_OPER_MODE_FORWARD_SINGLETAG:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            pDmFilterRule->outerTagIf = 0;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            pDmFilterRule->innerTagIf = 1;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
            if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
            {
                pDmFilterRule->innerTagTpid=OMCI_DEFAULT_CTAG_TPID;
            }
            else
            {
                pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(pDmFilterRule->innerTagTpid));
            }
            break;
        case VLAN_OPER_MODE_FILTER_INNER_PRI:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            pDmFilterRule->innerTagIf = 1;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
            if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
            {
                pDmFilterRule->innerTagTpid=OMCI_DEFAULT_CTAG_TPID;
            }
            else
            {
                pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(pDmFilterRule->innerTagTpid));
            }
            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
            }
            break;
        case VLAN_OPER_MODE_VLANTAG_OPER:
        case VLAN_OPER_MODE_FILTER_SINGLETAG:
            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID ||
                    pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
            }
            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI ||
                    pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
            }

            /*pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
            pDmFilterRule->innerTagTpid = pVlanRule->filterRule.filterCTag.tpid;*/
            break;
        case VLAN_OPER_MODE_EXTVLAN:
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;

            if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG &&
                pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_TAG)
            {
                pDmFilterRule->outerTagIf = 0;
                pDmFilterRule->innerTagIf = 0;
            }

            else if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG &&
                !(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_TAG))
            {
                pDmFilterRule->outerTagIf = 0;
                pDmFilterRule->innerTagIf = 1;
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
                pDmFilterRule->innerTagTpid=OMCI_DEFAULT_CTAG_TPID;
                
                pf_rt_dm_GetInnerVlanFilterRule(pVlanRule->filterRule.filterCtagMode, 
                    &pVlanRule->filterRule.filterCTag, pDmFilterRule);
            }

            else if(!(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG) &&
                pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_TAG)
            {
                pDmFilterRule->outerTagIf = 0;
                pDmFilterRule->innerTagIf = 1;

                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
                pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(pDmFilterRule->innerTagTpid));
                
                pf_rt_dm_GetInnerVlanFilterRule(pVlanRule->filterRule.filterStagMode, 
                    &pVlanRule->filterRule.filterSTag, pDmFilterRule);
            }

            else
            {
                pDmFilterRule->outerTagIf = 1;
                pDmFilterRule->innerTagIf = 1;

                pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TPID_BIT;
                pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(pDmFilterRule->outerTagTpid));

                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
                pDmFilterRule->innerTagTpid=OMCI_DEFAULT_CTAG_TPID;
                
                pf_rt_dm_GetOuterVlanFilterRule(pVlanRule->filterRule.filterStagMode, 
                    &pVlanRule->filterRule.filterSTag, pDmFilterRule);
                
                pf_rt_dm_GetInnerVlanFilterRule(pVlanRule->filterRule.filterCtagMode, 
                    &pVlanRule->filterRule.filterCTag, pDmFilterRule);
            }
            pf_rt_dm_GetEthertypeFilterRule(pVlanRule->filterRule.filterStagMode, 
                pVlanRule->filterRule.etherType, pDmFilterRule);

            pf_rt_dm_GetEthertypeFilterRule(pVlanRule->filterRule.filterCtagMode, 
                pVlanRule->filterRule.etherType, pDmFilterRule);


            pf_rt_dm_GetDscpFilterRule(pVlanRule->filterRule.filterStagMode,
                &pVlanRule->filterRule.filterDscp[0], pDmFilterRule); 


            pf_rt_dm_GetDscpFilterRule(pVlanRule->filterRule.filterCtagMode,
                &pVlanRule->filterRule.filterDscp[0], pDmFilterRule);
#if 0
            //
            // set stag filter
            //
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;

            if (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
                pDmFilterRule->outerTagIf = 0;
            else
                pDmFilterRule->outerTagIf = 1;

            if (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
                pDmFilterRule->outerTagVid = pVlanRule->filterRule.filterSTag.vid;
            }

            if (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                pDmFilterRule->outerTagPri = pVlanRule->filterRule.filterSTag.pri;
            }

            if (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
            {
                pDmFilterRule->filterMask |=
                    (OMCI_DM_FILTER_OUTER_VID_BIT | OMCI_DM_FILTER_OUTER_PRI_BIT);
                pDmFilterRule->outerTagVid = pVlanRule->filterRule.filterSTag.vid;
                pDmFilterRule->outerTagPri = pVlanRule->filterRule.filterSTag.pri;
            }

            if (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_ETHTYPE)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
                pDmFilterRule->etherType = pVlanRule->filterRule.etherType;
            }

            //
            // TBD: pFilter->filterStagMode & VLAN_FILTER_DSCP_PRI)
            //

            //
            // set ctag filter
            //
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_TAG)
                pDmFilterRule->innerTagIf = 0;
            else
                pDmFilterRule->innerTagIf = 1;

            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
            }

            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
            }

            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
            {
                pDmFilterRule->filterMask |=
                    (OMCI_DM_FILTER_INNER_VID_BIT | OMCI_DM_FILTER_INNER_PRI_BIT);
                pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
                pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
            }
            if (pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_ETHTYPE)
            {

                if (ETHTYPE_FILTER_IP == pVlanRule->filterRule.etherType)
                {
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
                    pDmFilterRule->etherType = 0x0800;
                }

                if (ETHTYPE_FILTER_PPPOE== pVlanRule->filterRule.etherType)
                {
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
                    pDmFilterRule->etherType = 0x8863;
                }


                if (ETHTYPE_FILTER_ARP == pVlanRule->filterRule.etherType)
                {
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
                    pDmFilterRule->etherType = 0x0806;
                }

                if (ETHTYPE_FILTER_PPPOE_S== pVlanRule->filterRule.etherType)
                {
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
                    pDmFilterRule->etherType = 0x8864;
                }

                if (ETHTYPE_FILTER_IPV6 == pVlanRule->filterRule.etherType)
                {
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_ETHERTYPE;
                    pDmFilterRule->etherType = 0x86dd;
                }
            }

#endif            
            //
            // TBD: pFilter->filterCtagMode & VLAN_FILTER_DSCP_PRI
            //
            break;
        }
        default:
            break;
    }
        return OMCI_ERR_OK;
}

static int pf_rt_dm_GetDsFilterRule(OMCI_VLAN_OPER_ts *pVlanRule, omci_dm_filter_rule_t *pDmFilterRule)
{
    int cTag=0;
    unsigned int sTag=0, sTpid=0, sVid=0, sPri=0;
    omci_dm_filter_mask_t sMask=0;
    
    if(NULL == pVlanRule || NULL == pDmFilterRule)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }
    switch(pVlanRule->cTagAct.vlanAct)
    {
        case VLAN_ACT_NON:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            pDmFilterRule->outerTagIf = 0;
            break;
        case VLAN_ACT_ADD:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            pDmFilterRule->innerTagIf = 1;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
            pDmFilterRule->innerTagTpid = OMCI_DEFAULT_CTAG_TPID;
            cTag++;
            break;
        case VLAN_ACT_REMOVE:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            pDmFilterRule->outerTagIf = 0;
            break;
        case VLAN_ACT_MODIFY:
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            pDmFilterRule->innerTagIf = 1;
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
            pDmFilterRule->innerTagTpid = OMCI_DEFAULT_CTAG_TPID;
            cTag++;
            break;
        case VLAN_ACT_TRANSPARENT:
            if(pVlanRule->filterMode == VLAN_OPER_MODE_FORWARD_ALL)
            {
                /*Forward all, filter nothing*/
            }
            else if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_TAG)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
                pDmFilterRule->outerTagIf = 0;
            }
            else
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
                pDmFilterRule->innerTagIf = 1;
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
                pDmFilterRule->innerTagTpid = OMCI_DEFAULT_CTAG_TPID;
                cTag=1;
            }    
            break;
        default:
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
               return OMCI_ERR_FAILED;
            break;
    }
    if(pVlanRule->cTagAct.vlanAct != VLAN_ACT_REMOVE && pVlanRule->cTagAct.vlanAct != VLAN_ACT_NON)
    {
        if(pVlanRule->cTagAct.vlanAct == VLAN_ACT_TRANSPARENT)
        {
            if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
            }
            if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
            {
                pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
            }
        }
        else
        {
            switch(pVlanRule->cTagAct.vidAct)
            {
                case VID_ACT_ASSIGN:
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                    pDmFilterRule->innerTagVid = pVlanRule->cTagAct.assignVlan.vid;
                    break;
                case VID_ACT_COPY_INNER:
                    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                    {
                        pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                        pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
                    }
                    break;
                case VID_ACT_COPY_OUTER:
                    if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
                    {
                        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                        {
                            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                            pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
                        }
                    }
                    else
                    {
                        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
                        {
                            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                            pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterSTag.vid;
                        }
                    }
                    break;
                case VID_ACT_TRANSPARENT:
                    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                    {
                        pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
                        pDmFilterRule->innerTagVid = pVlanRule->filterRule.filterCTag.vid;
                    }
                    break;
                default:
                    OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
                       return OMCI_ERR_FAILED;
                    break;
            }
            switch(pVlanRule->cTagAct.priAct)
            {
                case PRI_ACT_ASSIGN:
                    pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                    pDmFilterRule->innerTagPri = pVlanRule->cTagAct.assignVlan.pri;
                    break;
                case PRI_ACT_COPY_INNER:
                    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                    {
                        pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                        pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
                    }
                    break;
                case PRI_ACT_COPY_OUTER:
                    if((pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG) || (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG))
                    {
                        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                        {
                            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                            pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
                        }
                    }
                    else
                    {
                        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
                        {
                            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                            pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterSTag.pri;
                        }
                    }
                    break;
                case PRI_ACT_FROM_DSCP:
                    break;
                case PRI_ACT_TRANSPARENT:
                    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                    {
                        pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
                        pDmFilterRule->innerTagPri = pVlanRule->filterRule.filterCTag.pri;
                    }
                    break;
                default:
                    OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
                       return OMCI_ERR_FAILED;
                    break;
            }
        }
    }
    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_ETHTYPE)
    {
        pf_rt_dm_GetEthertypeFilterRule(VLAN_FILTER_ETHTYPE,pVlanRule->filterRule.etherType,pDmFilterRule);
    }


    /* Stag filter */
    switch(pVlanRule->sTagAct.vlanAct)
    {
        case VLAN_ACT_NON:
            sMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            sTag = 0;
            break;
        case VLAN_ACT_ADD:
            sMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            sTag = 1;
            sMask |= OMCI_DM_FILTER_OUTER_TPID_BIT;
            break;
        case VLAN_ACT_REMOVE:
            sMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            sTag = 0;
            break;
        case VLAN_ACT_MODIFY:
            sMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            sTag = 1;
            sMask |= OMCI_DM_FILTER_OUTER_TPID_BIT;
            break;
        case VLAN_ACT_TRANSPARENT:
            if(pVlanRule->filterMode != VLAN_OPER_MODE_FORWARD_ALL)
            {
                sMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
                if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
                {
                    sTag = 0;
                }
                else
                {
                    sTag = 1;
                    sMask |= OMCI_DM_FILTER_OUTER_TPID_BIT;
                }
            }
            break;
        default:
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
               return OMCI_ERR_FAILED;
            break;
    }
    if(sMask & OMCI_DM_FILTER_OUTER_TPID_BIT)
    {
        switch(pVlanRule->outStyle.tpid)
        {
            case TPID_8100:
                sTpid = 0x8100;
                break;
            case TPID_88A8:
                sTpid = 0x88A8;
                break;
            case TPID_0800:
                sTpid = 0x0800;
                break;
            case TPID_9100:
                sTpid = 0x9100;
                break;
            default:
                OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d unsupport TPID", __FUNCTION__, __LINE__);
                break;
        }
    }
    if(pVlanRule->sTagAct.vlanAct != VLAN_ACT_NON && pVlanRule->sTagAct.vlanAct != VLAN_ACT_REMOVE)
    {
        if(pVlanRule->sTagAct.vlanAct == VLAN_ACT_TRANSPARENT)
        {
            if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
            {
                sMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
                sVid = pVlanRule->filterRule.filterCTag.vid;
            }
            if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
            {
                sMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                sPri = pVlanRule->filterRule.filterCTag.pri;
            }
        }
        else
        {
            switch(pVlanRule->sTagAct.vidAct)
            {
                case VID_ACT_ASSIGN:
                    if(pVlanRule->sTagAct.vlanAct != VLAN_ACT_TRANSPARENT)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
                        sVid = pVlanRule->sTagAct.assignVlan.vid;
                    }
                    break;
                case VID_ACT_COPY_INNER:
                    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
                        sVid = pVlanRule->filterRule.filterCTag.vid;
                    }
                    break;
                case VID_ACT_COPY_OUTER:
                    if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
                        sVid = pVlanRule->filterRule.filterSTag.vid;
                    }
                    break;
                case VID_ACT_TRANSPARENT:
                    if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
                        sVid = pVlanRule->filterRule.filterSTag.vid;
                    }
                    break;
                default:
                    OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
                       return OMCI_ERR_FAILED;
                    break;
            }
            switch(pVlanRule->sTagAct.priAct)
            {
                case PRI_ACT_ASSIGN:
                    if(pVlanRule->sTagAct.vlanAct != VLAN_ACT_TRANSPARENT)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                        sPri = pVlanRule->sTagAct.assignVlan.pri;
                    }
                    break;
                case PRI_ACT_COPY_INNER:
                    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                        sPri = pVlanRule->filterRule.filterCTag.pri;
                    }
                    break;
                case PRI_ACT_COPY_OUTER:
                    if((pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_CARE_TAG) || (pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG))
                    {
                        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
                        {
                            sMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                            sPri = pVlanRule->filterRule.filterCTag.pri;
                        }
                    }
                    else
                    {
                        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
                        {
                            sMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                            sPri = pVlanRule->filterRule.filterSTag.pri;
                        }
                    }
                    break;
                case PRI_ACT_FROM_DSCP:
                    break;
                case PRI_ACT_TRANSPARENT:
                    if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
                    {
                        sMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
                        sPri = pVlanRule->filterRule.filterCTag.pri;
                    }
                    break;
                default:
                    OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s() %d parameter error", __FUNCTION__, __LINE__);
                       return OMCI_ERR_FAILED;
                    break;
            }
        }
    }
    if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_ETHTYPE)
    {
        pf_rt_dm_GetEthertypeFilterRule(VLAN_FILTER_ETHTYPE,pVlanRule->filterRule.etherType,pDmFilterRule);
    }

    if(cTag)
    {
        if(sMask & OMCI_DM_FILTER_OUTER_TAGIf_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TAGIf_BIT;
            pDmFilterRule->outerTagIf = sTag;
        }
        if(sMask & OMCI_DM_FILTER_OUTER_TPID_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_TPID_BIT;
            pDmFilterRule->outerTagTpid = sTpid;
        }
        if(sMask & OMCI_DM_FILTER_OUTER_VID_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_VID_BIT;
            pDmFilterRule->outerTagVid = sVid;
        }
        if(sMask & OMCI_DM_FILTER_OUTER_PRI_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_OUTER_PRI_BIT;
            pDmFilterRule->outerTagPri = sPri;
        }
    }
    else
    {
        if(sMask & OMCI_DM_FILTER_OUTER_TAGIf_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TAGIf_BIT;
            pDmFilterRule->innerTagIf = sTag;
        }
        if(sMask & OMCI_DM_FILTER_OUTER_TPID_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_TPID_BIT;
            pDmFilterRule->innerTagTpid = sTpid;
        }
        if(sMask & OMCI_DM_FILTER_OUTER_VID_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_VID_BIT;
            pDmFilterRule->innerTagVid = sVid;
        }
        if(sMask & OMCI_DM_FILTER_OUTER_PRI_BIT)
        {
            pDmFilterRule->filterMask |= OMCI_DM_FILTER_INNER_PRI_BIT;
            pDmFilterRule->innerTagPri = sPri;
        }
    }
    if(pVlanRule->filterMode == VLAN_OPER_MODE_FILTER_SINGLETAG)
    {
        pDmFilterRule->filterMask &= (~OMCI_DM_FILTER_INNER_TAGIf_BIT);
        pDmFilterRule->filterMask &= (~OMCI_DM_FILTER_OUTER_TAGIf_BIT);
        pDmFilterRule->innerTagIf = 0;
        pDmFilterRule->outerTagIf = 0;
        pDmFilterRule->filterMask &= (~OMCI_DM_FILTER_OUTER_TPID_BIT);
        pDmFilterRule->filterMask &= (~OMCI_DM_FILTER_INNER_TPID_BIT);
    }
    return OMCI_ERR_OK;
}

static int pf_rt_dm_GetDsAction(OMCI_VLAN_OPER_ts *pVlanRule, omci_pon_wan_vlan_action_t *pOuterAction, omci_pon_wan_vlan_action_t *pInnerAction, int filterTag)
{
    omci_pon_wan_vlan_action_t *sTagAction;
    int cTag=0;
    /* Ctag action*/
    if(pVlanRule->cTagAct.vlanAct == VLAN_ACT_TRANSPARENT || pVlanRule->cTagAct.vlanAct == VLAN_ACT_NON)
    {
        pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
    }
    else
    {
        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_CARE_TAG)
        {
            if(filterTag == 0)
            {
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
            else
            {
                cTag=1;
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
        }
        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_CARE_TAG)
        {
            cTag=1;
            pInnerAction->assignedTpid=OMCI_DEFAULT_CTAG_TPID;
            if(filterTag == 0)
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            else
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
        }
        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_NO_TAG)
        {
            if(filterTag == 0)
            {
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
            else
            {
                cTag=1;
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
        }
        else
        {
            cTag=1;
            pInnerAction->assignedTpid=OMCI_DEFAULT_CTAG_TPID;
            if(filterTag == 0)
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            else
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
        }
        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID)
        {
            cTag=1;
            pInnerAction->assignedTpid=OMCI_DEFAULT_CTAG_TPID;
            if(filterTag == 0)
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            else
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_ASSIGN;
            pInnerAction->assignedVid=pVlanRule->filterRule.filterCTag.vid;
        }
        else
        {
            pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
        }
        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI)
        {
            cTag=1;
            pInnerAction->assignedTpid=OMCI_DEFAULT_CTAG_TPID;
            if(filterTag == 0)
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            else
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_ASSIGN;
            pInnerAction->assignedPri=pVlanRule->filterRule.filterCTag.pri;
        }
        else
        {
            pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
        }
        if(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI)
        {
            cTag=1;
            pInnerAction->assignedTpid=OMCI_DEFAULT_CTAG_TPID;
            if(filterTag == 0)
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            else
                pInnerAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_ASSIGN;
            pInnerAction->assignedVid=pVlanRule->filterRule.filterCTag.vid;
            pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_ASSIGN;
            pInnerAction->assignedPri=pVlanRule->filterRule.filterCTag.pri;
            //pOuterAction->tagDeiAction=OMCI_PON_WAN_VLAN_DEI_ASSIGN;
            //pOuterAction->assignedDei=pVlanRule->filterRule.filterCTag.dei;
        }

        if(pInnerAction->tagAction == OMCI_PON_WAN_VLAN_TAGIF_TAGGING || pInnerAction->tagAction == OMCI_PON_WAN_VLAN_TAGIF_MODIFY)
        {
            if(!(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI))
            {
                if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
                {
                    if(pVlanRule->cTagAct.vidAct == VID_ACT_COPY_OUTER)
                    {
                        if(pVlanRule->sTagAct.vlanAct == VLAN_ACT_ADD)
                        {
                            pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_2ND_TAG;
                        }
                        else
                        {
                            pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_1ST_TAG;
                        }
                    }
                    else if(pVlanRule->sTagAct.vidAct == VID_ACT_COPY_OUTER)
                    {
                        pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_1ST_TAG;
                    }
                }
                else
                {
                    if(pVlanRule->cTagAct.vidAct == VID_ACT_COPY_INNER)
                    {
                        pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_2ND_TAG;
                    }
                    else if(pVlanRule->sTagAct.vidAct == VID_ACT_COPY_INNER)
                    {
                        pInnerAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_1ST_TAG;
                    }
                }
            }

            if(!(pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterCtagMode & VLAN_FILTER_TCI))
            {
                if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
                {
                    if(pVlanRule->cTagAct.priAct == PRI_ACT_COPY_OUTER)
                    {
                        if(pVlanRule->sTagAct.vlanAct == VLAN_ACT_ADD)
                        {
                            pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_2ND_TAG;
                        }
                        else
                        {
                            pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_1ST_TAG;
                        }
                    }
                    else if(pVlanRule->sTagAct.priAct == PRI_ACT_COPY_OUTER)
                    {
                        pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_1ST_TAG;
                    }
                }
                else
                {
                    if(pVlanRule->cTagAct.priAct == PRI_ACT_COPY_INNER)
                    {
                        pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_2ND_TAG;
                    }
                    else if(pVlanRule->sTagAct.priAct == PRI_ACT_COPY_INNER)
                    {
                        pInnerAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_1ST_TAG;
                    }
                }
            }
        }
    }
    if(cTag)
    {
        sTagAction=pOuterAction;
    }
    else
    {
        sTagAction=pInnerAction;
        
    }
    /* Stag action */
    if(pVlanRule->sTagAct.vlanAct == VLAN_ACT_TRANSPARENT || pVlanRule->sTagAct.vlanAct == VLAN_ACT_NON)
    {
        sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
    }
    else
    {
        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_CARE_TAG)
        {
            if(filterTag>cTag)
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
            else
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
        }
        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_CARE_TAG)
        {
            sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        }
        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_NO_TAG)
        {
            if(filterTag > cTag)
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
            else
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
        }
        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID)
        {
            sTagAction->assignedTpid=OMCI_DEFAULT_STAG_TPID;
            if(filterTag < cTag+1)
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            }
            else
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            }
            sTagAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_ASSIGN;
            sTagAction->assignedVid=pVlanRule->filterRule.filterSTag.vid;
        }
        else
        {
            sTagAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
        }
        
        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI)
        {
            sTagAction->assignedTpid=OMCI_DEFAULT_STAG_TPID;
            if(filterTag < cTag+1)
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            }
            else
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            }
            sTagAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_ASSIGN;
            sTagAction->assignedPri=pVlanRule->filterRule.filterSTag.pri;
        }
        else
        {
            sTagAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
        }
        if(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI)
        {
            sTagAction->assignedTpid=OMCI_DEFAULT_STAG_TPID;
            if(filterTag < cTag+1)
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_TAGGING;
            }
            else
            {
                sTagAction->tagAction=OMCI_PON_WAN_VLAN_TAGIF_MODIFY;
            }
            sTagAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_ASSIGN;
            sTagAction->assignedVid=pVlanRule->filterRule.filterSTag.vid;
            sTagAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_ASSIGN;
            sTagAction->assignedPri=pVlanRule->filterRule.filterSTag.pri;
            //sTagAction->tagDeiAction=OMCI_PON_WAN_VLAN_DEI_ASSIGN;
            //sTagAction->assignedDei=pVlanRule->filterRule.filterSTag.dei;
        }

        if(sTagAction->tagAction == OMCI_PON_WAN_VLAN_TAGIF_TAGGING || sTagAction->tagAction == OMCI_PON_WAN_VLAN_TAGIF_MODIFY)
        {
            if(!(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_VID || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI))
            {
                if(pVlanRule->cTagAct.vidAct == VID_ACT_COPY_OUTER)
                {
                    sTagAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_2ND_TAG;
                }
                else if(pVlanRule->sTagAct.vidAct == VID_ACT_COPY_OUTER)
                {
                    sTagAction->tagVidAction=OMCI_PON_WAN_VLAN_VID_COPY_FROM_1ST_TAG;
                }
            }

            if(!(pVlanRule->filterRule.filterStagMode & VLAN_FILTER_PRI || pVlanRule->filterRule.filterStagMode & VLAN_FILTER_TCI))
            {
                if(pVlanRule->cTagAct.priAct == PRI_ACT_COPY_OUTER)
                {
                    sTagAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_2ND_TAG;
                }
                else if(pVlanRule->sTagAct.priAct == PRI_ACT_COPY_OUTER)
                {
                    sTagAction->tagPriAction=OMCI_PON_WAN_VLAN_PRI_COPY_FROM_1ST_TAG;
                }
            }
        }
    }

    return OMCI_ERR_OK;    
}

static int pf_rt_dm_GetDsPriAct(OMCI_BRIDGE_RULE_ts *pRule, omci_dm_ds_pri_act_t *pDsPriAct, unsigned int *pri)
{
    flow2DsPq_entry_t   *pEntry = NULL;

    if (!pRule || !pDsPriAct || !pri)
        return OMCI_ERR_PARAM;

    pEntry = flow2DsPq_entry_find(pRule->dsFlowId);

    *pDsPriAct = OMCI_DM_DS_PRI_ACT_NOP;
    *pri = 0;

    if (!pEntry)
        return OMCI_ERR_OK;

    if (0xFFFF == pEntry->dsQ.dsPqOmciPri)
        return OMCI_ERR_OK;

    if (PQ_DROP_COLOUR_NO_MARKING != pEntry->dsQ.dpMarking)
        return OMCI_ERR_OK;
    
    if ((pRule->uniMask & (1 << gPlatformDb.ponPort)) ||/*VEIP rule*/
         ((1 << pEntry->dsQ.portId) &  pRule->uniMask)) /*PPTP rule*/
    {
        *pDsPriAct = OMCI_DM_DS_PRI_ACT_ASSIGN;
        *pri = pEntry->dsQ.priority;
    }

    return OMCI_ERR_OK;

}

static int pf_rt_dm_GetL2Info_DsDftCnt(void)
{
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;
    int dsDftCnt = 0;

    list_for_each_safe(pEntry, pTmpEntry, &gL2DsDftHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);            
        dsDftCnt++;
    }

    return dsDftCnt;

}

/*Maintain which L2 connection is releated with Downstream default rule*/
static int pf_rt_dm_AddL2DsDftRue(unsigned int connectionId)
{

    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;

    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%x", __FUNCTION__, __LINE__, connectionId);

    list_for_each_safe(pEntry, pTmpEntry, &gL2DsDftHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (pEntryData->connectionId == connectionId)
        {            
            return OMCI_ERR_OK;
        }
    }

    /*Entry no found ,add new entry*/
    pEntryData = (omci_connection_info_t*)kmalloc(sizeof(omci_connection_info_t),GFP_KERNEL);
    pEntryData->connectionId = connectionId;
    list_add_tail(&pEntryData->list,&gL2DsDftHead);

    return OMCI_ERR_OK; 

}



static int pf_rt_dm_AddL2Info(unsigned int connectionId)
{
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;

    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%x", __FUNCTION__, __LINE__, connectionId);

    list_for_each_safe(pEntry, pTmpEntry, &gL2FlowHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (pEntryData->connectionId == connectionId)
        {
            return OMCI_ERR_OK;
        }
    }

    /*Entry no found ,add new entry*/

    pEntryData = (omci_connection_info_t*)kmalloc(sizeof(omci_connection_info_t),GFP_KERNEL);
    pEntryData->connectionId = connectionId;
    list_add_tail(&pEntryData->list,&gL2FlowHead);
    
    return OMCI_ERR_OK;    
}

static int pf_rt_dm_DelL2InfoBySeverId(unsigned int serverId)
{
    int32                     ret;
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;
    int dsDftCnt = 0;

    list_for_each_safe(pEntry, pTmpEntry, &gL2FlowHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (CONNECTION_ID_TO_SERVER_ID(pEntryData->connectionId) == serverId)
        {

            ret =  pDmmCb->omci_dm_l2_info_del(pEntryData->connectionId);
            if (RT_ERR_OK != ret)
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                    "del dm l2 info fail, ret = %d", ret);
            }

            OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%d", __FUNCTION__, __LINE__, pEntryData->connectionId);

            list_del(&pEntryData->list);

            kfree(pEntryData);

        }
    }

    dsDftCnt = pf_rt_dm_GetL2Info_DsDftCnt();

    if(0 == dsDftCnt)
        return OMCI_ERR_OK;

    /*Check if L2 Downstream default rule is need to delete*/
    list_for_each_safe(pEntry, pTmpEntry, &gL2DsDftHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (CONNECTION_ID_TO_SERVER_ID(pEntryData->connectionId) == serverId)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%d", __FUNCTION__, __LINE__, pEntryData->connectionId);

            list_del(&pEntryData->list);

            kfree(pEntryData);

            if(1 == dsDftCnt)
            {
                ret =  pDmmCb->omci_dm_l2_info_del(DS_DFT_CONNECTION_ID);
                if (RT_ERR_OK != ret)
                {
                    OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                        "del dm l2 info ds default connection fail, ret = %d", ret);
                }
            }

        }
    }

    return OMCI_ERR_OK;
}

static int pf_rt_dm_GetVeipInfo_DsDftCnt(void)
{
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;
    int dsDftCnt = 0;

    list_for_each_safe(pEntry, pTmpEntry, &gVeipDsDftHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);            
        dsDftCnt++;
    }

    return dsDftCnt;

}

/*Mainain which connection is releated with VEIP Downstream default rule*/
static int pf_rt_dm_AddVeipDsDftRue(unsigned int connectionId)
{

    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;

    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%x", __FUNCTION__, __LINE__, connectionId);

    list_for_each_safe(pEntry, pTmpEntry, &gVeipDsDftHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (pEntryData->connectionId == connectionId)
        {            
            return OMCI_ERR_OK;
        }
    }

    /*Entry no found ,add new entry*/
    pEntryData = (omci_connection_info_t*)kmalloc(sizeof(omci_connection_info_t),GFP_KERNEL);
    pEntryData->connectionId = connectionId;
    list_add_tail(&pEntryData->list,&gVeipDsDftHead);

    return OMCI_ERR_OK; 

}


static int pf_rt_dm_AddVeipInfo(unsigned int connectionId)
{
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;

    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%x", __FUNCTION__, __LINE__, connectionId);

    list_for_each_safe(pEntry, pTmpEntry, &gVeipFlowHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (pEntryData->connectionId == connectionId)
        {

            return OMCI_ERR_OK;

        }
    }

    /*Entry no found ,add new entry*/

    pEntryData = (omci_connection_info_t*)kmalloc(sizeof(omci_connection_info_t),GFP_KERNEL);
    pEntryData->connectionId = connectionId;
    list_add_tail(&pEntryData->list,&gVeipFlowHead);
    
    return OMCI_ERR_OK;    
}

static int pf_rt_dm_DelVeipInfoBySeverId(unsigned int serverId)
{
    int32                     ret;
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    omci_connection_info_t    *pEntryData;
    int dsDftCnt = 0;

    list_for_each_safe(pEntry, pTmpEntry, &gVeipFlowHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (CONNECTION_ID_TO_SERVER_ID(pEntryData->connectionId) == serverId)
        {

            ret =  pDmmCb->omci_dm_veip_info_del(pEntryData->connectionId);
            if (RT_ERR_OK != ret)
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                    "del dm veip info fail, ret = %d", ret);
            }

            OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%d", __FUNCTION__, __LINE__, pEntryData->connectionId);

            list_del(&pEntryData->list);

            kfree(pEntryData);

        }
    }

    dsDftCnt = pf_rt_dm_GetVeipInfo_DsDftCnt();

    if(0 == dsDftCnt)
        return OMCI_ERR_OK;


    /*Check VEIP downstream default rule is need to delete*/
    list_for_each_safe(pEntry, pTmpEntry, &gVeipDsDftHead)
    {
        pEntryData = list_entry(pEntry, omci_connection_info_t, list);

        if (CONNECTION_ID_TO_SERVER_ID(pEntryData->connectionId) == serverId)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d, connectionId:%d", __FUNCTION__, __LINE__, pEntryData->connectionId);

            list_del(&pEntryData->list);

            kfree(pEntryData);

            if(1 == dsDftCnt)
            {
                ret =  pDmmCb->omci_dm_veip_info_del(DS_DFT_CONNECTION_ID);
                if (RT_ERR_OK != ret)
                {
                    OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                        "del dm veip info ds default connection fail, ret = %d", ret);
                }
            }

        }
    }

    return OMCI_ERR_OK;
}


#ifdef DM_DEBUG
void showDmDsPriAction(omci_dm_ds_pri_act_t dsPriAct, unsigned int dsPriority)
{
    switch(dsPriAct)
    {
        case OMCI_DM_DS_PRI_ACT_NOP:
            printk(KERN_EMERG "\x1b[1;31mdsPriAct: NOP\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_TAGIF_TAGGING:
            printk(KERN_EMERG "\x1b[1;31mdsPriAct: Assign PRI\x1b[0m\n");
            break;
        default:
            printk(KERN_EMERG "\x1b[1;31mdsPriAct: Unknown\x1b[0m\n");
            break;
    }

    printk(KERN_EMERG "\x1b[1;31mdsPriority:0x%04x\x1b[0m\n",dsPriority); 
}

void showDmAction(omci_pon_wan_vlan_action_t *pActionInfo)
{
    switch(pActionInfo->tagAction)
    {
        case OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT:
            printk(KERN_EMERG "\x1b[1;31mTagAction: Transparent\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_TAGIF_TAGGING:
            printk(KERN_EMERG "\x1b[1;31mTagAction: Add\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_TAGIF_MODIFY:
            printk(KERN_EMERG "\x1b[1;31mTagAction: Modify\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_TAGIF_REMOVE:
            printk(KERN_EMERG "\x1b[1;31mTagAction: Remove\x1b[0m\n");
            break;
        default:
            printk(KERN_EMERG "\x1b[1;31mTagAction: Unknown\x1b[0m\n");
            break;
    }

    switch(pActionInfo->tagTpidAction)
    {
        case OMCI_PON_WAN_VLAN_TPID_ASSIGN:
            printk(KERN_EMERG "\x1b[1;31mTpidAction: Assign\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_TPID_COPY_FROM_1ST_TAG:
            printk(KERN_EMERG "\x1b[1;31mTpidAction: Copy from 1st tag\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_TPID_COPY_FROM_2ND_TAG:
            printk(KERN_EMERG "\x1b[1;31mTpidAction: Copy from 2nd tag\x1b[0m\n");
            break;
        default:
            printk(KERN_EMERG "\x1b[1;31mTpidAction: Unknown\x1b[0m\n");
            break;
    }

    switch(pActionInfo->tagVidAction)
    {
        case OMCI_PON_WAN_VLAN_VID_ASSIGN:
            printk(KERN_EMERG "\x1b[1;31mVidAction: Assign\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_VID_COPY_FROM_1ST_TAG:
            printk(KERN_EMERG "\x1b[1;31mVidAction: Copy from 1st tag\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_VID_COPY_FROM_2ND_TAG:
            printk(KERN_EMERG "\x1b[1;31mVidAction: Copy from 2nd tag\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_VID_TRANSPARENT:
            printk(KERN_EMERG "\x1b[1;31mVidAction: Transparent\x1b[0m\n");
            break;
        default:
            printk(KERN_EMERG "\x1b[1;31mTpidAction: Unknown\x1b[0m\n");
            break;
    }

    switch(pActionInfo->tagPriAction)
    {
        case OMCI_PON_WAN_VLAN_PRI_ASSIGN:
            printk(KERN_EMERG "\x1b[1;31mPriAction: Assign\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_PRI_COPY_FROM_1ST_TAG:
            printk(KERN_EMERG "\x1b[1;31mPriAction: Copy from 1st tag\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_PRI_COPY_FROM_2ND_TAG:
            printk(KERN_EMERG "\x1b[1;31mPriAction: Copy from 2nd tag\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_PRI_COPY_FROM_DSCP_REMAP:
            printk(KERN_EMERG "\x1b[1;31mPriAction: Copy from DSCP\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_PRI_TRANSPARENT:
            printk(KERN_EMERG "\x1b[1;31mPriAction: Transparent\x1b[0m\n");
            break;
        default:
            printk(KERN_EMERG "\x1b[1;31mPriAction: Unknown\x1b[0m\n");
            break;
    }

    switch(pActionInfo->tagDeiAction)
    {
        case OMCI_PON_WAN_VLAN_DEI_ASSIGN:
            printk(KERN_EMERG "\x1b[1;31mDeiAction: Assign\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_DEI_COPY_FROM_1ST_TAG:
            printk(KERN_EMERG "\x1b[1;31mDeiAction: Copy from 1st tag\x1b[0m\n");
            break;
        case OMCI_PON_WAN_VLAN_DEI_COPY_FROM_2ND_TAG:
            printk(KERN_EMERG "\x1b[1;31mDeiAction: Copy from 2nd tag\x1b[0m\n");
            break;
        default:
            printk(KERN_EMERG "\x1b[1;31mDeiAction: Unknown\x1b[0m\n");
            break;
    }

    printk(KERN_EMERG "\x1b[1;31mTPID:0x%04x\x1b[0m\n",pActionInfo->assignedTpid);
    printk(KERN_EMERG "\x1b[1;31mVID:%d\x1b[0m\n",pActionInfo->assignedVid);
    printk(KERN_EMERG "\x1b[1;31mPri:0x%04x\x1b[0m\n",pActionInfo->assignedPri);
    printk(KERN_EMERG "\x1b[1;31mDei:0x%04x\x1b[0m\n",pActionInfo->assignedDei);
}


void showDmFilterRule(omci_dm_filter_rule_t *pFilterInfo)
{
    UINT8 i;
    printk(KERN_EMERG "\x1b[1;31mFilter Mask:\x1b[0m\n");
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_FLOWID_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mFlowID, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_OUTER_TAGIf_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mOuterTag, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_INNER_TAGIf_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mInnerTag, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_OUTER_TPID_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mOuterTpid, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_OUTER_VID_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mOuterVid, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_OUTER_PRI_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mOuterPri, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_OUTER_DEI_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mOuterDei, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_INNER_TPID_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mInnerTpid, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_INNER_VID_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mInnerVid, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_INNER_PRI_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mInnerPbit, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_INNER_DEI_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mInnerDei, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_ETHERTYPE)
    {
        printk(KERN_EMERG "\x1b[1;31mEtherType, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_DSCP_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mDSCP, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_EGRESS_PORT_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mEgressPort, \x1b[0m");
    }
    if(pFilterInfo->filterMask & OMCI_DM_FILTER_EGRESS_IF_ID_BIT)
    {
        printk(KERN_EMERG "\x1b[1;31mEgressIf, \x1b[0m");
    }
    printk(KERN_EMERG "\x1b[1;31m\x1b[0m\n");
    printk(KERN_EMERG "\x1b[1;31mFlowID:%d\x1b[0m\n",pFilterInfo->flowId);
    printk(KERN_EMERG "\x1b[1;31mOuterTag:%d\x1b[0m\n",pFilterInfo->outerTagIf);
    printk(KERN_EMERG "\x1b[1;31mOuterTpid:0x%04x\x1b[0m\n",pFilterInfo->outerTagTpid);
    printk(KERN_EMERG "\x1b[1;31mOuterVid:%d\x1b[0m\n",pFilterInfo->outerTagVid);
    printk(KERN_EMERG "\x1b[1;31mOuterPri:%d\x1b[0m\n",pFilterInfo->outerTagPri);
    printk(KERN_EMERG "\x1b[1;31mOuterDei:%d\x1b[0m\n\n",pFilterInfo->outerTagDei);
    printk(KERN_EMERG "\x1b[1;31mInnerTag:%d\x1b[0m\n",pFilterInfo->innerTagIf);
    printk(KERN_EMERG "\x1b[1;31mInnerTpid:0x%04x\x1b[0m\n",pFilterInfo->innerTagTpid);
    printk(KERN_EMERG "\x1b[1;31mInnerVid:%d\x1b[0m\n",pFilterInfo->innerTagVid);
    printk(KERN_EMERG "\x1b[1;31mInnerPri:%d\x1b[0m\n",pFilterInfo->innerTagPri);
    printk(KERN_EMERG "\x1b[1;31mInnerDei:%d\x1b[0m\n\n",pFilterInfo->innerTagDei);
    printk(KERN_EMERG "\x1b[1;31mEtherType:0x%04x\x1b[0m\n",pFilterInfo->etherType);
    printk(KERN_EMERG "\x1b[1;31mDSCP:\x1b[0m");
    for(i=0;i<8;i++)
    {
        printk(KERN_EMERG "\x1b[1;31m%02x, \x1b[0m",pFilterInfo->dscp[i]);
    }
    printk(KERN_EMERG "\x1b[1;31m\x1b[0m\n");
    printk(KERN_EMERG "\x1b[1;31mEgressPort:0x%x\x1b[0m\n",pFilterInfo->egressPortMask);
    printk(KERN_EMERG "\x1b[1;31mEgressIf:%d\x1b[0m\n",pFilterInfo->egressIfId);
    
}


void showDmRule(omci_dm_veip_info_t *pRuleInfo)
{
    printk(KERN_EMERG "\x1b[1;33mConnectionId=%d\x1b[0m\n",pRuleInfo->connectionId);
    if(pRuleInfo->direction == OMCI_RULE_DIR_ONLY_US)
    {
        printk(KERN_EMERG "\x1b[1;31mDirection=US\x1b[0m\n");
    }
    if(pRuleInfo->direction == OMCI_RULE_DIR_ONLY_DS)
    {
        printk(KERN_EMERG "\x1b[1;31mDirection=DS\x1b[0m\n");
    }
    else
    {
        printk(KERN_EMERG "\x1b[1;31mDirection=BOTH\x1b[0m\n");
    }
    printk(KERN_EMERG "\x1b[1;31mFlowID=%d\x1b[0m\n",pRuleInfo->flowId);
    printk(KERN_EMERG "\x1b[1;32mDsFilterRule:\x1b[0m\n");
    showDmFilterRule(&(pRuleInfo->dsFilterRule));
    printk(KERN_EMERG "\n\x1b[1;31mDsOuterAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->dsOuterTagAct));
    printk(KERN_EMERG "\n\x1b[1;31mDsInnerAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->dsInnerTagAct));

    printk(KERN_EMERG "\n\n\x1b[1;32mUsFilterRule:\x1b[0m\n");
    showDmFilterRule(&(pRuleInfo->usFilterRule));
    printk(KERN_EMERG "\n\x1b[1;31mUsOuterAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->usOuterTagAct));
    printk(KERN_EMERG "\n\x1b[1;31mUsInnerAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->usInnerTagAct));

    printk(KERN_EMERG "\n\x1b[1;31mDsPriAction:\x1b[0m\n");
    showDmDsPriAction(pRuleInfo->dsPriorityAct,pRuleInfo->dsPriority);
    
}

void showDmL2Rule(omci_dm_l2_info_t *pRuleInfo)
{
    printk(KERN_EMERG "\x1b[1;33mConnectionId=%x\x1b[0m\n",pRuleInfo->connectionId);
    if(pRuleInfo->direction == OMCI_RULE_DIR_ONLY_US)
    {
        printk(KERN_EMERG "\x1b[1;31mDirection=US\x1b[0m\n");
    }
    else if(pRuleInfo->direction == OMCI_RULE_DIR_ONLY_DS)
    {
        printk(KERN_EMERG "\x1b[1;31mDirection=DS\x1b[0m\n");
    }
    else
    {
        printk(KERN_EMERG "\x1b[1;31mDirection=BOTH\x1b[0m\n");
    }
    printk(KERN_EMERG "\x1b[1;31mBridgeID=%d\x1b[0m\n",pRuleInfo->briIdx);
    printk(KERN_EMERG "\x1b[1;31mFlowID=%d\x1b[0m\n",pRuleInfo->flowId);
    printk(KERN_EMERG "\x1b[1;31mUNI port=0x%x\x1b[0m\n",pRuleInfo->ingressPortMask);
    printk(KERN_EMERG "\x1b[1;32mDsFilterRule:\x1b[0m\n");
    showDmFilterRule(&(pRuleInfo->dsFilterRule));
    printk(KERN_EMERG "\n\x1b[1;31mDsOuterAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->dsOuterTagAct));
    printk(KERN_EMERG "\n\x1b[1;31mDsInnerAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->dsInnerTagAct));

    printk(KERN_EMERG "\n\x1b[1;31mDsPriAction:\x1b[0m\n");
    showDmDsPriAction(pRuleInfo->dsPriorityAct,pRuleInfo->dsPriority);


    printk(KERN_EMERG "\n\n\x1b[1;32mUsFilterRule:\x1b[0m\n");
    showDmFilterRule(&(pRuleInfo->usFilterRule));
    printk(KERN_EMERG "\n\x1b[1;31mUsOuterAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->usOuterTagAct));
    printk(KERN_EMERG "\n\x1b[1;31mUsInnerAction:\x1b[0m\n");
    showDmAction(&(pRuleInfo->usInnerTagAct));
    
}


#endif



static int pf_rt_GetDsPriActionByDpMarkVal(int dsDpMarking, int pri, omci_dm_ds_pri_act_t *pRetDsPriAct, unsigned int *pDsRetPri)
{
    if(*pRetDsPriAct || !pDsRetPri)
        return OMCI_ERR_PARAM;

    *pRetDsPriAct = OMCI_DM_DS_PRI_ACT_ASSIGN;

    if(PQ_DROP_COLOUR_PCP_5P3D_MARKING == dsDpMarking)
    {
        if(0==pri || 2==pri || 4==pri)
            *pDsRetPri = 0;
        else
            *pDsRetPri = 1;
            
    }
    else if(PQ_DROP_COLOUR_PCP_6P2D_MARKING == dsDpMarking)
    {
        if(2==pri || 4==pri)
            *pDsRetPri = 0;
        else
            *pDsRetPri = 1; 
            
    }
    else if(PQ_DROP_COLOUR_PCP_7P1D_MARKING == dsDpMarking)
    {
        if(4==pri)
            *pDsRetPri = 0;
        else
            *pDsRetPri = 1;
            
    }
    else
    {
         *pDsRetPri = 1;
    }

     return OMCI_ERR_OK;   
}

static int pf_rt_GetUsFlowdByDpMarkVal(int usDpMarking, int usOrigFlowId, int usDpFlowId, int pri, int *pRetUsFlowId)
{
    if(!pRetUsFlowId)
        return OMCI_ERR_PARAM;


    if(PQ_DROP_COLOUR_PCP_5P3D_MARKING == usDpMarking)
    {
        if(0==pri || 2==pri || 4==pri)
            *pRetUsFlowId = usDpFlowId;
        else
            *pRetUsFlowId = usOrigFlowId;
            
    }
    else if(PQ_DROP_COLOUR_PCP_6P2D_MARKING == usDpMarking)
    {
        if(2==pri || 4==pri)
            *pRetUsFlowId = usDpFlowId;
        else
            *pRetUsFlowId = usOrigFlowId; 
            
    }
    else if(PQ_DROP_COLOUR_PCP_7P1D_MARKING == usDpMarking)
    {
        if(4==pri)
            *pRetUsFlowId = usDpFlowId;
        else
            *pRetUsFlowId = usOrigFlowId; 
            
    }
    else
    {
        *pRetUsFlowId = usOrigFlowId;

    }
    return OMCI_ERR_OK;        
}


static int pf_rt_UpdateRuleByExtVlanDsMode(
    OMCI_VLAN_OPER_ts *pVlanRule, 
    omci_dm_filter_rule_t *pDmFilterRule, 
    omci_pon_wan_vlan_action_t *pInnerVlanAction,
    omci_pon_wan_vlan_action_t *pOUterVlanAction,
    int *pIsSkipSetRule,  
    int *pIsAddExtraDftRule)
{
    if (!pVlanRule || !pDmFilterRule || !pInnerVlanAction ||
        !pOUterVlanAction || !pIsSkipSetRule || !pIsAddExtraDftRule
        )
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d Parameter error", __FUNCTION__, __LINE__);
        return OMCI_ERR_PARAM;
    }

    *pIsSkipSetRule  = 0;
    *pIsAddExtraDftRule  = 0;

    if(VLAN_OPER_MODE_EXTVLAN == pVlanRule->filterMode)
    {
        switch(pVlanRule->outStyle.dsMode) 
        {
            case DS_MODE1_ALL_FORWARD:                
                *pIsSkipSetRule = 1;
                *pIsAddExtraDftRule = 1;
                break;
            case DS_MODE2_FILTER_VID_PRI_OTHER_FORWARD:
                *pIsAddExtraDftRule = 1;
                break;
            case DS_MODE3_FILTER_VID_OTHER_FORWARD:                
                /*Ingore DS PBIT check*/
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_FLOWID_BIT;    
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_INNER_PRI_BIT;
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_OUTER_PRI_BIT;
                pInnerVlanAction->tagPriAction = OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
                pOUterVlanAction->tagPriAction = OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
                *pIsAddExtraDftRule = 1;
                break;
            case DS_MODE4_FILTER_PRI_OTHER_FORWARD:                
                /*Ingore DS VID check*/
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_INNER_VID_BIT;
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_OUTER_VID_BIT;
                pInnerVlanAction->tagVidAction = OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
                pOUterVlanAction->tagVidAction = OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
                *pIsAddExtraDftRule = 1;
                break;
            case DS_MODE6_FILTER_VID_OTHER_DROP:                
                /*Ingore DS PBIT check*/
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_FLOWID_BIT;
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_INNER_PRI_BIT;
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_OUTER_PRI_BIT;
                pInnerVlanAction->tagPriAction = OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
                pOUterVlanAction->tagPriAction = OMCI_PON_WAN_VLAN_PRI_TRANSPARENT;
                break;
            case DS_MODE7_FILTER_PRI_OTHER_DROP:               
                /*Ingore DS VID check*/
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_INNER_VID_BIT;
                pDmFilterRule->filterMask &= ~OMCI_DM_FILTER_OUTER_VID_BIT;
                pInnerVlanAction->tagVidAction = OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
                pOUterVlanAction->tagVidAction = OMCI_PON_WAN_VLAN_VID_TRANSPARENT;
                break;            
            case DS_MODE8_ALL_DROP:
                *pIsSkipSetRule = 1;
                break;
        }

    }

    return OMCI_ERR_OK;  
}

static int pf_rt_IsDpRule(OMCI_BRIDGE_RULE_ts *pBridgeRule, BOOL *pIsDpRule)
{
    flow2DsPq_entry_t   *pEntry = NULL;

    if (!pBridgeRule || !pIsDpRule)
        return OMCI_ERR_PARAM;


    *pIsDpRule = 0;

    
    /*Check upstream*/
    switch(pBridgeRule->usDpMarking)
    {
        case PQ_DROP_COLOUR_DEI_MARKING:
        case PQ_DROP_COLOUR_PCP_8P0D_MARKING:
        case PQ_DROP_COLOUR_PCP_7P1D_MARKING:
        case PQ_DROP_COLOUR_PCP_6P2D_MARKING:
        case PQ_DROP_COLOUR_PCP_5P3D_MARKING:
            *pIsDpRule = 1;
            break;
    }

    /*Check downstream*/

    pEntry = flow2DsPq_entry_find(pBridgeRule->dsFlowId);

    if (!pEntry)
        return OMCI_ERR_OK;

    if (0xFFFF == pEntry->dsQ.dsPqOmciPri)
        return OMCI_ERR_OK;

    switch(pEntry->dsQ.dpMarking)
    {
        case PQ_DROP_COLOUR_DEI_MARKING:
        case PQ_DROP_COLOUR_PCP_8P0D_MARKING:
        case PQ_DROP_COLOUR_PCP_7P1D_MARKING:
        case PQ_DROP_COLOUR_PCP_6P2D_MARKING:
        case PQ_DROP_COLOUR_PCP_5P3D_MARKING:
            *pIsDpRule = 1;
            break;
    }

    return OMCI_ERR_OK;
}

static int pf_rt_SetDsFlow2Queue(OMCI_GEM_FLOW_ts *pDsFlow)
{
    flow2DsPq_entry_t   *pEntry = NULL;
    if(!pDsFlow)
        return OMCI_ERR_PARAM;

    if (pDsFlow->ena)
    {
        // insert
        pEntry = flow2DsPq_entry_find(pDsFlow->flowId);
        if (pEntry)
        {
            memcpy(&(pEntry->dsQ), &(pDsFlow->dsQInfo), sizeof(OMCI_DS_PQ_INFO));
        }
        else
        {
            if (OMCI_ERR_OK != flow2DsPq_entry_add(pDsFlow->flowId, pDsFlow->portId, &(pDsFlow->dsQInfo)))
               return OMCI_ERR_FAILED;
        }
    }
    else
    {
        if (OMCI_ERR_OK != flow2DsPq_entry_del(pDsFlow->flowId))
            return OMCI_ERR_FAILED;
    }

    return OMCI_ERR_OK;
}

/*
veip maintain
*/


static int
pf_rt_DelMBcastRule(unsigned int servId)
{
    int             ret;
    mbcast_service_t  *pEntry;

    pEntry = mbcastServ_entry_find(servId);
    if (!pEntry)
        return OMCI_ERR_OK;

    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_ds_mc_bc_info_del))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }

    if (gDrvCtrl.dmMode)
    {
        ret = pDmmCb->omci_dm_ds_mc_bc_info_del(servId);
        if (0 != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                "del mbcast rule:%d by dmm fail, ret = %d", servId, ret);

            return OMCI_ERR_FAILED;
        }

    }
    mbcastServ_entry_del(servId);

    return OMCI_ERR_OK;
}

static int
pf_rt_DelAllMBcastRule(void)
{
    mbcast_service_t  *pMBcastEntry;
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;

    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_ds_mc_bc_info_del))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }

    list_for_each_safe(pEntry, pTmpEntry, &gPlatformDb.mbcastHead)
    {
        pMBcastEntry = list_entry(pEntry, mbcast_service_t, list);
        // del veip rule
        if (OMCI_ERR_OK != pf_rt_DelMBcastRule(pMBcastEntry->index))
        {

        }
    }

    return OMCI_ERR_OK;
}


static int
pf_rt_DelL2Rule(unsigned int servId)
{
    int             ret;
    l2_service_t  *pEntry;

    pEntry = l2Serv_entry_find(servId);
    if (!pEntry)
        return OMCI_ERR_OK;

    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_l2_info_del))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }

    if (gDrvCtrl.dmMode)
    {
        ret = pf_rt_dm_DelL2InfoBySeverId(servId);
        if (OMCI_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                "del l2 rule:%d by dmm fail, ret = %d", servId, ret);

            return OMCI_ERR_FAILED;
        }

    }
    l2Serv_entry_del(servId);
    return OMCI_ERR_OK;
}

static int
pf_rt_DelAllL2Rule(void)
{
    l2_service_t  *pL2Entry;
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;


    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_l2_info_del))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }

    list_for_each_safe(pEntry, pTmpEntry, &gPlatformDb.l2Head)
    {
        pL2Entry = list_entry(pEntry, l2_service_t, list);
        // del l2 rule
        if (OMCI_ERR_OK != pf_rt_DelL2Rule(pL2Entry->index))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d delete l2 index:%d fail", 
                __FUNCTION__, __LINE__, pL2Entry->index);
        }
    }

    return OMCI_ERR_OK;
}

static int
pf_rt_DelVeipRule(unsigned int servId)
{
    int             ret;

    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_veip_info_del))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }

    if (gDrvCtrl.dmMode)
    {
        ret = pf_rt_dm_DelVeipInfoBySeverId(servId);
        if (OMCI_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                "del veip rule:%d by dmm for fail, ret = %d", servId, ret);

            return OMCI_ERR_FAILED;
        }

    }
    veipServ_entry_del(servId);

    return OMCI_ERR_OK;
}

static int
pf_rt_DelAllVeipRule(void)
{
    veip_service_t  *pVeipEntry;
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;


    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_veip_info_del))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }

    list_for_each_safe(pEntry, pTmpEntry, &gPlatformDb.veipHead)
    {
        pVeipEntry = list_entry(pEntry, veip_service_t, list);
        // del veip rule
        if (OMCI_ERR_OK != pf_rt_DelVeipRule(pVeipEntry->index))
        {

        }
    }

    return OMCI_ERR_OK;
}

/*Set L2 drop precedence*/
static int pf_rt_SetVeipDpRule(OMCI_BRIDGE_RULE_ts *pBridgeRule, omci_dm_veip_info_t *pOrigDmVeipInfo)
{
    int32                     ret;
    omci_dm_veip_info_t       dmVeipInfo[2];
    flow2DsPq_entry_t       *pEntry = NULL;
    int pri;
    unsigned int usDrvDpFlowId,usDrvFlowId;
    BOOL bUsExtraRuleSet = FALSE; 
    BOOL bDsExtraRuleSet = FALSE; 
    
    if (!pBridgeRule || !pOrigDmVeipInfo)
        return OMCI_ERR_PARAM;

    /*index 0=> refer orignal rule,index 1=> new rule*/
    memcpy(&dmVeipInfo[0], pOrigDmVeipInfo, sizeof(omci_dm_veip_info_t));
    memset(&dmVeipInfo[1], 0x0, sizeof(omci_dm_veip_info_t));

    if(PON_GEMPORT_DIRECTION_US == pBridgeRule->dir || PON_GEMPORT_DIRECTION_BI == pBridgeRule->dir)
    {
        ret = omci_qos_GetUsDrvFlowId(pBridgeRule->usDpFlowId, &usDrvDpFlowId); 
        if(OMCI_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get drv flow id fail usDpFlowId:%d, ret:%d", 
                __FUNCTION__, __LINE__, pBridgeRule->usDpFlowId, ret);
            return OMCI_ERR_FAILED;
        }


        /*Check upstream */
        if(PQ_DROP_COLOUR_DEI_MARKING == pBridgeRule->usDpMarking)
        {
        
            /*DEI 0 uses orignal flowID(high queue)*/
            dmVeipInfo[0].usFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmVeipInfo[0].usFilterRule.innerTagDei   = 0;


            /*DEI 1 uses DP flowID(low queue)*/
            bUsExtraRuleSet    =   TRUE;
            memcpy(&dmVeipInfo[1].usFilterRule, &dmVeipInfo[0].usFilterRule, sizeof(omci_dm_filter_rule_t));
            memcpy(&dmVeipInfo[1].usOuterTagAct, &dmVeipInfo[0].usOuterTagAct, sizeof(omci_pon_wan_vlan_action_t));
            memcpy(&dmVeipInfo[1].usInnerTagAct, &dmVeipInfo[0].usInnerTagAct, sizeof(omci_pon_wan_vlan_action_t));
            dmVeipInfo[1].direction   = OMCI_RULE_DIR_ONLY_US;
            dmVeipInfo[1].usFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmVeipInfo[1].usFilterRule.innerTagDei   = 1;
            dmVeipInfo[1].flowId          = usDrvDpFlowId;

        }
        else
        {
            if(pOrigDmVeipInfo->usFilterRule.filterMask & OMCI_DM_FILTER_INNER_PRI_BIT)
            {
                pri = pOrigDmVeipInfo->usFilterRule.innerTagPri;
                pf_rt_GetUsFlowdByDpMarkVal(pBridgeRule->usDpMarking, pOrigDmVeipInfo->flowId, usDrvDpFlowId, pri, &usDrvFlowId);
                dmVeipInfo[0].flowId          = usDrvFlowId;
                OMCI_LOG(OMCI_LOG_LEVEL_INFO, "%s:%d flowId:%d pri:%d", __FUNCTION__, __LINE__, dmVeipInfo[0].flowId, pri);
            }

        }
    }

    /*Check downstream*/
    if(PON_GEMPORT_DIRECTION_DS == pBridgeRule->dir || PON_GEMPORT_DIRECTION_BI == pBridgeRule->dir)
    {
        pEntry = flow2DsPq_entry_find(pBridgeRule->dsFlowId);

        if (!pEntry)
            goto SET_VEIP_INFO;

        if (0xFFFF == pEntry->dsQ.dsPqOmciPri)
            goto SET_VEIP_INFO;


        if(PQ_DROP_COLOUR_DEI_MARKING == pEntry->dsQ.dpMarking)
        {
            /*DEI 0 uses high queue*/
            dmVeipInfo[0].dsFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmVeipInfo[0].dsFilterRule.innerTagDei   = 0;
            dmVeipInfo[0].dsPriorityAct   =   OMCI_DM_DS_PRI_ACT_ASSIGN;
            dmVeipInfo[0].dsPriority      =   1;

            bDsExtraRuleSet    =   TRUE;
            memcpy(&dmVeipInfo[1].dsFilterRule, &dmVeipInfo[0].dsFilterRule, sizeof(omci_dm_filter_rule_t));
            memcpy(&dmVeipInfo[1].dsOuterTagAct, &dmVeipInfo[0].dsOuterTagAct, sizeof(omci_pon_wan_vlan_action_t));
            memcpy(&dmVeipInfo[1].dsInnerTagAct, &dmVeipInfo[0].dsInnerTagAct, sizeof(omci_pon_wan_vlan_action_t));
            dmVeipInfo[1].dsFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmVeipInfo[1].dsFilterRule.innerTagDei   = 1;
            dmVeipInfo[1].dsPriorityAct   =   OMCI_DM_DS_PRI_ACT_ASSIGN;
            dmVeipInfo[1].dsPriority      =   0;

            if(TRUE == bUsExtraRuleSet)
                dmVeipInfo[1].direction   = OMCI_RULE_DIR_BOTH;
            else
                dmVeipInfo[1].direction   = OMCI_RULE_DIR_ONLY_DS;            


        }
        else
        {
            if(pOrigDmVeipInfo->dsFilterRule.filterMask & OMCI_DM_FILTER_INNER_PRI_BIT)
            {
                pri = pOrigDmVeipInfo->dsFilterRule.innerTagPri;
                pf_rt_GetDsPriActionByDpMarkVal(pEntry->dsQ.dpMarking, pri, &dmVeipInfo[0].dsPriorityAct, &dmVeipInfo[0].dsPriority);
                OMCI_LOG(OMCI_LOG_LEVEL_INFO, "%s:%d flowId:%d  pri:%d", __FUNCTION__, __LINE__, dmVeipInfo[1].flowId, pri);
            }

        }
    }

 SET_VEIP_INFO:

    dmVeipInfo[0].connectionId = TO_CONNECTION_ID(pBridgeRule->servId, 0);

#ifdef DM_DEBUG
    showDmRule(&dmVeipInfo[0]);
#endif

    ret =  pDmmCb->omci_dm_veip_info_set(&dmVeipInfo[0]);
    if (RT_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d veip dmm set fail ", __FUNCTION__, __LINE__);
    } 
    pf_rt_dm_AddVeipInfo(dmVeipInfo[0].connectionId);




    if(TRUE == bUsExtraRuleSet || TRUE == bDsExtraRuleSet)
    {
        dmVeipInfo[1].connectionId = TO_CONNECTION_ID(pBridgeRule->servId, 1);
#ifdef DM_DEBUG
        showDmRule(&dmVeipInfo[1]);
#endif
        ret =  pDmmCb->omci_dm_veip_info_set(&dmVeipInfo[1]);
        if (RT_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d veip dmm set fail ", __FUNCTION__, __LINE__);
        }
        pf_rt_dm_AddVeipInfo(dmVeipInfo[1].connectionId);
        

    }


    return OMCI_ERR_OK;

}

static int omcidrv_IpHostToVeIpRule(OMCI_BRIDGE_RULE_ts *pNew,
                                    OMCI_BRIDGE_RULE_ts *pCur)
{
    int ignore_uni = FALSE;

    if (!pNew || !pCur)
        return OMCI_ERR_FAILED;

    memcpy(pNew, pCur, sizeof(OMCI_BRIDGE_RULE_ts));

    if ((VLAN_FILTER_NO_TAG & pCur->vlanRule.filterRule.filterStagMode) &&
        (VLAN_FILTER_NO_TAG & pCur->vlanRule.filterRule.filterCtagMode))
        ignore_uni = TRUE;

    if (VLAN_FILTER_NO_CARE_TAG & pCur->vlanRule.filterRule.filterCtagMode)
        ignore_uni = TRUE;

    if (ignore_uni)
    {
        if (pCur->vlanRule.outStyle.outTagNum)
        {
            pNew->vlanRule.filterRule.filterCtagMode = VLAN_FILTER_VID;
            pNew->vlanRule.filterRule.filterCTag.vid = pCur->vlanRule.outStyle.outVlan.vid;
        }
        else
        {
            pNew->vlanRule.filterRule.filterCtagMode = VLAN_FILTER_NO_CARE_TAG;
        }
    }
    return OMCI_ERR_OK;
}

static int
pf_rt_SetVeipRule(OMCI_BRIDGE_RULE_ts  *pBridgeRule)
{
    int                                       ret;
    OMCI_VLAN_OPER_ts   *pVlanRule;
    omci_dm_veip_info_t dmVeipInfo;
    unsigned int usDrvFlowId;
    OMCI_VLAN_ACT_ts *pStagAct, *pCtagAct;
    int finalTag;
    BOOL                    bIsVeipDpRule = FALSE;
    OMCI_VLAN_FILTER_ts     fakeDsfilter;
    BOOL isSkipSetDsRule = FALSE;
    BOOL isAddExtraDsRule = FALSE;

    
    if (!pBridgeRule)
        return OMCI_ERR_FAILED;

    if (NULL == pDmmCb || 
        NULL == pDmmCb->omci_dm_veip_info_set ||
        NULL == pDmmCb->omci_dm_veip_info_del)
    {

        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d dmm callback is not registered", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    ret =  pf_rt_dm_DelVeipInfoBySeverId(pBridgeRule->servId);
    if (OMCI_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "del dm veip info fail, ret = %d", ret);
    }

    pVlanRule = &pBridgeRule->vlanRule;

    memset(&dmVeipInfo, 0, sizeof(dmVeipInfo));
    dmVeipInfo.connectionId = pBridgeRule->servId;

    switch(pBridgeRule->dir)
    {
        case PON_GEMPORT_DIRECTION_US:
            dmVeipInfo.direction = OMCI_RULE_DIR_ONLY_US;
            break;
        case PON_GEMPORT_DIRECTION_DS:
            dmVeipInfo.direction = OMCI_RULE_DIR_ONLY_DS;
            break;
        case PON_GEMPORT_DIRECTION_BI:
            dmVeipInfo.direction = OMCI_RULE_DIR_BOTH;
            break;
        default:
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, unknown direction %d", 
                __FUNCTION__, __LINE__, pBridgeRule->dir);
            return OMCI_ERR_FAILED;
            break;
    }

    ret = omci_qos_GetUsDrvFlowId(pBridgeRule->usFlowId, &usDrvFlowId);    

    if(OMCI_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get drv flow id fail usFlowId:%d, ret:%d", 
            __FUNCTION__, __LINE__, pBridgeRule->usFlowId, ret);
        return OMCI_ERR_FAILED;
    }

    dmVeipInfo.flowId = usDrvFlowId;

    if(pBridgeRule->if_id != -1)
    {
        dmVeipInfo.usFilterRule.egressIfId = pBridgeRule->if_id;
        dmVeipInfo.usFilterRule.filterMask |= OMCI_DM_FILTER_EGRESS_IF_ID_BIT;
        dmVeipInfo.dsFilterRule.egressIfId = pBridgeRule->if_id;
        dmVeipInfo.dsFilterRule.filterMask |= OMCI_DM_FILTER_EGRESS_IF_ID_BIT;
    }

    if(OMCI_ERR_OK != pf_rt_dm_GetFilterRule(pVlanRule, &dmVeipInfo.usFilterRule))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get filter rule fail", __FUNCTION__, __LINE__);

    }

    pStagAct = &pVlanRule->sTagAct;
    pCtagAct = &pVlanRule->cTagAct;
    
    /*Stag/Ctag TRANSPARENT*/
    if(VLAN_ACT_TRANSPARENT == pStagAct->vlanAct && VLAN_ACT_TRANSPARENT == pCtagAct->vlanAct)
    {
        dmVeipInfo.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        dmVeipInfo.usInnerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
    }
    /*Stag TRANSPARENT*/
    else if(VLAN_ACT_TRANSPARENT == pStagAct->vlanAct && VLAN_ACT_TRANSPARENT != pCtagAct->vlanAct)
    {
        dmVeipInfo.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        if(pVlanRule->filterRule.filterStagMode == VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterStagMode == VLAN_FILTER_NO_TAG)
            finalTag=1;
        else
            finalTag=2;
        if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmVeipInfo.usInnerTagAct,finalTag,dmVeipInfo.usFilterRule.innerTagIf+dmVeipInfo.usFilterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

        }
        dmVeipInfo.usInnerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
    }
    /*Ctag TRANSPARENT*/
    else if(VLAN_ACT_TRANSPARENT != pStagAct->vlanAct && VLAN_ACT_TRANSPARENT == pCtagAct->vlanAct)
    {
        dmVeipInfo.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        if(pVlanRule->filterRule.filterCtagMode == VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterCtagMode == VLAN_FILTER_NO_TAG)
            finalTag=1;
        else
            finalTag=2;
        if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmVeipInfo.usInnerTagAct,finalTag,dmVeipInfo.usFilterRule.innerTagIf+dmVeipInfo.usFilterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
        }
        pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmVeipInfo.usInnerTagAct.assignedTpid));
    }

    else
    {
        if(VLAN_ACT_REMOVE == pCtagAct->vlanAct && VLAN_ACT_REMOVE != pStagAct->vlanAct)
        {
            if(dmVeipInfo.usFilterRule.outerTagIf == 0)
            {
                dmVeipInfo.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
            else
            {
                dmVeipInfo.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmVeipInfo.usInnerTagAct,1,dmVeipInfo.usFilterRule.innerTagIf+dmVeipInfo.usFilterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
           pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmVeipInfo.usInnerTagAct.assignedTpid));
        }
        else if(VLAN_ACT_REMOVE != pCtagAct->vlanAct && VLAN_ACT_REMOVE == pStagAct->vlanAct)
        {
            dmVeipInfo.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmVeipInfo.usInnerTagAct,1,dmVeipInfo.usFilterRule.innerTagIf+dmVeipInfo.usFilterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
           dmVeipInfo.usInnerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
        else
        {
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmVeipInfo.usOuterTagAct,2,dmVeipInfo.usFilterRule.innerTagIf+dmVeipInfo.usFilterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }

            pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmVeipInfo.usOuterTagAct.assignedTpid));

            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmVeipInfo.usInnerTagAct,1,dmVeipInfo.usFilterRule.innerTagIf+dmVeipInfo.usFilterRule.outerTagIf))
            {

                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
            }

            dmVeipInfo.usInnerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
    }


    /*downstream*/
    if(pBridgeRule->dir != PON_GEMPORT_DIRECTION_US)
    {
        if(OMCI_ERR_OK != pf_rt_dm_GetDsFilterRule(pVlanRule, &dmVeipInfo.dsFilterRule))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get filter rule fail", __FUNCTION__, __LINE__);

        }
        dmVeipInfo.dsFilterRule.filterMask |= OMCI_DM_FILTER_FLOWID_BIT;
        dmVeipInfo.dsFilterRule.flowId = pBridgeRule->dsFlowId;
        if(OMCI_ERR_OK != pf_rt_dm_GetDsAction(pVlanRule, &dmVeipInfo.dsOuterTagAct, &dmVeipInfo.dsInnerTagAct,dmVeipInfo.dsFilterRule.innerTagIf+dmVeipInfo.dsFilterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get action fail", __FUNCTION__, __LINE__);

        }

        if(OMCI_ERR_OK != pf_rt_dm_GetDsPriAct(pBridgeRule, &dmVeipInfo.dsPriorityAct, &dmVeipInfo.dsPriority))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get DsPriAct fail", __FUNCTION__, __LINE__);

        }

        if(OMCI_ERR_OK != pf_rt_UpdateRuleByExtVlanDsMode(pVlanRule, &dmVeipInfo.dsFilterRule, &dmVeipInfo.dsInnerTagAct, 
            &dmVeipInfo.dsOuterTagAct,&isSkipSetDsRule, &isAddExtraDsRule))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, extVlan dsMode fail", __FUNCTION__, __LINE__);

        }

        if(isSkipSetDsRule)
        {
            dmVeipInfo.direction = OMCI_RULE_DIR_ONLY_US;              
        }

        /*Fake a vlan filter data to check is BDP 2 enable or not*/
        memset(&fakeDsfilter,0,sizeof(OMCI_VLAN_FILTER_ts));
        fakeDsfilter.filterStagMode = VLAN_FILTER_NO_TAG;
        fakeDsfilter.filterCtagMode = VLAN_FILTER_PRI;
        if (OMCIDRV_FEATURE_ERR_OK == omcidrv_feature_api(FEATURE_KAPI_BDP_00000002, &fakeDsfilter))
        {
            /*Ingore DS PBIT check*/
            dmVeipInfo.dsFilterRule.filterMask &= ~OMCI_DM_FILTER_INNER_PRI_BIT;
            dmVeipInfo.dsFilterRule.filterMask &= ~OMCI_DM_FILTER_OUTER_PRI_BIT;
        }
    }

    if(OMCI_ERR_OK != pf_rt_IsDpRule(pBridgeRule, &bIsVeipDpRule))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, check is L2 DP rule fail", __FUNCTION__, __LINE__);

    }


    if(TRUE == bIsVeipDpRule)
    {
        return pf_rt_SetVeipDpRule(pBridgeRule, &dmVeipInfo);
    }


#ifdef DM_DEBUG
    showDmRule(&dmVeipInfo);
#endif

    ret =  pDmmCb->omci_dm_veip_info_set(&dmVeipInfo);
    if (RT_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "add dm veip info fail, ret = %d", ret);
    }    
    pf_rt_dm_AddVeipInfo(dmVeipInfo.connectionId);


    if(TRUE == isAddExtraDsRule)
    {
        if(0 ==pf_rt_dm_GetVeipInfo_DsDftCnt())
        {
            dmVeipInfo.dsFilterRule.filterMask = 0;
            dmVeipInfo.direction = OMCI_RULE_DIR_ONLY_DS;
            dmVeipInfo.connectionId = DS_DFT_CONNECTION_ID;
            dmVeipInfo.dsInnerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            dmVeipInfo.dsOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;

            ret =  pDmmCb->omci_dm_veip_info_set(&dmVeipInfo);
            if (RT_ERR_OK != ret)
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                    "add dm L2 info extra rule fail, ret = %d", ret);
            }
        }
        pf_rt_dm_AddVeipDsDftRue(pBridgeRule->servId);

    }
   
    return OMCI_ERR_OK;
}

static int
pf_rt_updateMcastBcastRule ( mbcast_service_t* pMBEntry,
    OMCI_BRIDGE_RULE_ts* pDsRule )
{

    OMCI_VLAN_OPER_ts           *pVlanRule;
    OMCI_VLAN_ACT_ts            *pStagAct;
    OMCI_VLAN_ACT_ts            *pCtagAct;
    omci_dm_ds_bc_mc_info_t     dmBcMcInfo;
    int                         ret;
    int                         finalTag;
    OMCI_VLAN_FILTER_ts         fakeDsfilter;

    if (!pDsRule)
        return OMCI_ERR_FAILED;


    if (NULL == pDmmCb || 
            NULL == pDmmCb->omci_dm_ds_mc_bc_info_set ||
            NULL == pDmmCb->omci_dm_ds_mc_bc_info_del)
    {

        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d dmm ds MC callback is not registered", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }



    // delete old rule
    ret = pDmmCb->omci_dm_ds_mc_bc_info_del(pDsRule->servId);
    if (0 != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "del mc bc rule by dmm fail, ret = %d", ret);

        //return OMCI_ERR_FAILED;
    }

    pVlanRule = &pDsRule->vlanRule;
    pStagAct = &pVlanRule->sTagAct;
    pCtagAct = &pVlanRule->cTagAct;

    // skip entries that is destined to drop
    if (OMCI_EXTVLAN_REMOVE_TAG_DISCARD == pVlanRule->outStyle.isDefaultRule)
        return OMCI_ERR_FAILED;

    //
    // add new rule
    //
    memset(&dmBcMcInfo, 0, sizeof(omci_dm_ds_bc_mc_info_t));

    dmBcMcInfo.connectionId = pDsRule->servId;
    dmBcMcInfo.isMcRule = pDsRule->vlanRule.outStyle.isMCRule;

    // set ds gem flow id
    dmBcMcInfo.filterRule.filterMask |= OMCI_DM_FILTER_FLOWID_BIT;
    dmBcMcInfo.filterRule.flowId = pDsRule->dsFlowId;

    // set dst port mask
    dmBcMcInfo.filterRule.filterMask |= OMCI_DM_FILTER_EGRESS_PORT_BIT;
    if (pDsRule->uniMask & (1 << gPlatformDb.ponPort))
        dmBcMcInfo.filterRule.egressPortMask = (gPlatformDb.uniPortMask | gPlatformDb.extPortMask);
    else
        dmBcMcInfo.filterRule.egressPortMask = pDsRule->uniMask;

    /* set filter */

    if(OMCI_ERR_OK != pf_rt_dm_GetFilterRule(pVlanRule, &dmBcMcInfo.filterRule))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get filter rule fail", __FUNCTION__, __LINE__);

    }


    if (OMCIDRV_FEATURE_ERR_OK == omcidrv_feature_api(FEATURE_KAPI_RDP_00000002))
    {
        pStagAct->vlanAct = VLAN_ACT_REMOVE;
        pCtagAct->vlanAct = VLAN_ACT_REMOVE;
    }    


    /*Stag/Ctag TRANSPARENT*/
    if(VLAN_ACT_TRANSPARENT == pStagAct->vlanAct && VLAN_ACT_TRANSPARENT == pCtagAct->vlanAct)
    {
        dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        dmBcMcInfo.innerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
    }
    /*Stag TRANSPARENT*/
    else if(VLAN_ACT_TRANSPARENT == pStagAct->vlanAct && VLAN_ACT_TRANSPARENT != pCtagAct->vlanAct)
    {
        dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        if(pVlanRule->filterRule.filterStagMode == VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterStagMode == VLAN_FILTER_NO_TAG)
            finalTag=1;
        else
            finalTag=2;
        if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmBcMcInfo.innerTagAct,finalTag, dmBcMcInfo.filterRule.innerTagIf + dmBcMcInfo.filterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

        }
        dmBcMcInfo.innerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
    }
    /*Ctag TRANSPARENT*/
    else if(VLAN_ACT_TRANSPARENT != pStagAct->vlanAct && VLAN_ACT_TRANSPARENT == pCtagAct->vlanAct)
    {
        dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        if(pVlanRule->filterRule.filterCtagMode == VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterCtagMode == VLAN_FILTER_NO_TAG)
            finalTag=1;
        else
            finalTag=2;
        if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmBcMcInfo.innerTagAct,finalTag, dmBcMcInfo.filterRule.innerTagIf + dmBcMcInfo.filterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

        }
        pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmBcMcInfo.innerTagAct.assignedTpid));
    }

    else
    {
        if(VLAN_ACT_REMOVE == pCtagAct->vlanAct && VLAN_ACT_REMOVE != pStagAct->vlanAct)
        {
            dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmBcMcInfo.innerTagAct,1, dmBcMcInfo.filterRule.innerTagIf + dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
        	pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmBcMcInfo.innerTagAct.assignedTpid));
        }
        else if(VLAN_ACT_REMOVE != pCtagAct->vlanAct && VLAN_ACT_REMOVE == pStagAct->vlanAct)
        {
            dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmBcMcInfo.innerTagAct,1, dmBcMcInfo.filterRule.innerTagIf + dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
            dmBcMcInfo.innerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
        else
        {
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmBcMcInfo.outerTagAct,2, dmBcMcInfo.filterRule.innerTagIf + dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
            pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmBcMcInfo.outerTagAct.assignedTpid));

            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmBcMcInfo.innerTagAct,1, dmBcMcInfo.filterRule.innerTagIf + dmBcMcInfo.filterRule.outerTagIf))
            {

                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
            }
            dmBcMcInfo.innerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
        if(VLAN_ACT_REMOVE == pCtagAct->vlanAct && VLAN_ACT_REMOVE != pStagAct->vlanAct)
        {
            if(dmBcMcInfo.filterRule.outerTagIf == 0)
            {
                dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
            else
            {
                dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmBcMcInfo.innerTagAct,1,dmBcMcInfo.filterRule.innerTagIf+dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
           pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmBcMcInfo.innerTagAct.assignedTpid));
        }
        else if(VLAN_ACT_REMOVE != pCtagAct->vlanAct && VLAN_ACT_REMOVE == pStagAct->vlanAct)
        {
            dmBcMcInfo.outerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmBcMcInfo.innerTagAct,1,dmBcMcInfo.filterRule.innerTagIf+dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
           dmBcMcInfo.innerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
        else
        {
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmBcMcInfo.outerTagAct,2,dmBcMcInfo.filterRule.innerTagIf+dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
            }

            pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmBcMcInfo.outerTagAct.assignedTpid));

            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmBcMcInfo.innerTagAct,1,dmBcMcInfo.filterRule.innerTagIf+dmBcMcInfo.filterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
            }

            dmBcMcInfo.innerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
    }

    if(OMCI_ERR_OK != pf_rt_dm_GetDsPriAct(pDsRule, &dmBcMcInfo.dsPriorityAct, &dmBcMcInfo.dsPriority))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get DsPriAct fail", __FUNCTION__, __LINE__);
    }

    /*Fake a vlan filter data to check is BDP 2 enable or not*/
    memset(&fakeDsfilter,0,sizeof(OMCI_VLAN_FILTER_ts));
    fakeDsfilter.filterStagMode = VLAN_FILTER_NO_TAG;
    fakeDsfilter.filterCtagMode = VLAN_FILTER_PRI;
    if (OMCIDRV_FEATURE_ERR_OK == omcidrv_feature_api(FEATURE_KAPI_BDP_00000002, &fakeDsfilter))
    {
        /*Ingore DS PBIT check*/
        dmBcMcInfo.filterRule.filterMask &= ~OMCI_DM_FILTER_INNER_PRI_BIT;
        dmBcMcInfo.filterRule.filterMask &= ~OMCI_DM_FILTER_OUTER_PRI_BIT;
    }


    ret =  pDmmCb->omci_dm_ds_mc_bc_info_set(&dmBcMcInfo);
    if (RT_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "add ds mc bc fail, ret = %d", ret);
    }

    return OMCI_ERR_OK;

}

static int pf_rt_CreateTcont(OMCI_TCONT_ts *pTcont)
{

    if(RT_ERR_OK != rt_gpon_tcont_set(&pTcont->tcontId, pTcont->allocId))
    {
       OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d set rt gpon tcont fail",
                __FUNCTION__,__LINE__);
            return OMCI_ERR_FAILED; 
    }
    
     OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d allocId:%d tcontId:%d",
        __FUNCTION__,__LINE__,pTcont->allocId,pTcont->tcontId);  

     _SetTcontDb(pTcont->tcontId, pTcont->allocId);
     
    return OMCI_ERR_OK;
}

static int pf_rt_UpdateTcont(OMCI_TCONT_ts *pTcont)
{
    if(RT_ERR_OK != rt_gpon_tcont_set(&pTcont->tcontId, pTcont->allocId))
    {
       OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d set rt gpon tcont fail",
                __FUNCTION__,__LINE__);
            return OMCI_ERR_FAILED; 
    }

     _SetTcontDb(pTcont->tcontId, pTcont->allocId);
    
    return OMCI_ERR_OK;
}


static int pf_rt_CfgGemFlow(OMCI_GEM_FLOW_ts *pGemFlow)
{
    int ret; 
    rt_gpon_dsFlow_t dsFlowCfg;
    rt_gpon_usFlow_t usFlowCfg;
    
    if(PON_GEMPORT_DIRECTION_DS == pGemFlow->dir)
    {
        if (pGemFlow->ena == TRUE)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_INFO,
                "%s() %d DS Enable flowId:%d portId:%d\n",
                __FUNCTION__,__LINE__,
                pGemFlow->flowId,
                pGemFlow->portId);
       
            memset(&dsFlowCfg, 0, sizeof(dsFlowCfg));
            dsFlowCfg.gemPortId = pGemFlow->portId;
            dsFlowCfg.isMcGem   = pGemFlow->isDsOnly;
            
            if(RT_ERR_OK != rt_gpon_dsFlow_set(pGemFlow->flowId,&dsFlowCfg))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d set ds gemflow:%d fail\n",__FUNCTION__,__LINE__,pGemFlow->flowId);
                return OMCI_ERR_FAILED;            
            }
        }
        else
        {
            OMCI_LOG(OMCI_LOG_LEVEL_INFO,
                "%s() %d DS disable flowId:%d\n",
                __FUNCTION__,__LINE__,
                pGemFlow->flowId)
                
            if(RT_ERR_OK != rt_gpon_dsFlow_del(pGemFlow->flowId))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d del ds gemflow:%d fail\n",__FUNCTION__,__LINE__, pGemFlow->flowId);
                return OMCI_ERR_FAILED;            
            }
        }

        if(OMCI_ERR_OK != pf_rt_SetDsFlow2Queue(pGemFlow))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d set ds gemflow:%d to queue fail\n",__FUNCTION__,__LINE__, pGemFlow->flowId);
            return OMCI_ERR_FAILED;            
        }
    }
    else
    {
        if (pGemFlow->ena == TRUE)
        {

            OMCI_LOG(OMCI_LOG_LEVEL_INFO,
                "%s() %d US enable flowId:%d portId:%d TCID:%d TQID:%d\n",
                __FUNCTION__,__LINE__,
                pGemFlow->flowId,pGemFlow->portId,
                pGemFlow->tcontId,pGemFlow->queueId);

            memset(&usFlowCfg, 0, sizeof(usFlowCfg));
            usFlowCfg.gemPortId     = pGemFlow->portId;
            usFlowCfg.tcontId       = pGemFlow->tcontId;
            usFlowCfg.tcQueueId     = pGemFlow->queueId;
            usFlowCfg.aesEn         = pGemFlow->encKeyRing == GEM_PORT_ENC_UC_BOTH_DIRECTION?1:0;

            ret = omci_qos_usFlow_set(pGemFlow->flowId,&usFlowCfg);
            if(OMCI_ERR_OK != ret)
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d set us flowId:%d fail,ret:%d",__FUNCTION__,__LINE__, pGemFlow->flowId, ret);
                return OMCI_ERR_FAILED;            
            }
        }
        else
        {

            OMCI_LOG(OMCI_LOG_LEVEL_INFO,
                "%s() %d US disable flowId:%d\n",
                __FUNCTION__,__LINE__,
                pGemFlow->flowId)

            if(RT_ERR_OK != omci_qos_usFlow_del(pGemFlow->flowId))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d del us gemflow:%d fail\n",__FUNCTION__,__LINE__, pGemFlow->flowId);
                return OMCI_ERR_FAILED;            
            }
        }

    }

    return OMCI_ERR_OK;
}


static int pf_rt_CfgGemRate(OMCI_GEM_FLOW_ts *pGemFlow)
{
    unsigned int pir;    
    OMCI_LOG(OMCI_LOG_LEVEL_WARN,
        "%s() %d flowId:%d CIR:%d PIR:%d",
        __FUNCTION__,__LINE__,pGemFlow->flowId,pGemFlow->pir,pGemFlow->cir);



    pir = pGemFlow->pir == 0?RT_GPON_PON_QUEUE_PIR_UNLIMITED:pGemFlow->pir;

    omci_qos_usFlowRate_set(pGemFlow->flowId, pir, pGemFlow->cir);
    return OMCI_ERR_OK;
}


static void omci_UpdateDpMarkingByPriQId(OMCI_PRIQ_ts *pPriQ)
{
    struct list_head        *pEntry     = NULL;
    struct list_head        *pTmpEntry  = NULL;
    flow2DsPq_entry_t       *pEntryData = NULL;
    rt_qos_queue_weights_t  weights;

    list_for_each_safe(pEntry, pTmpEntry, &gPlatformDb.flow2DsPqHead)
    {
        pEntryData = list_entry(pEntry, flow2DsPq_entry_t, list);

        if (pEntryData->dsQ.dsPqOmciPri == pPriQ->queueId)
        {
            pEntryData->dsQ.dpMarking = pPriQ->dpMarking;
            pEntryData->dsQ.policy = pPriQ->scheduleType;
            pEntryData->dsQ.weight = pPriQ->weight;
            memset(&weights, 0x00, sizeof(rt_qos_queue_weights_t));

            if(gPlatformDb.ponPort == pEntryData->dsQ.portId)
            {
                OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s(%d): skip to config schedulingQueue for VEIP priQ\n", __FUNCTION__, __LINE__);
                continue;                
            }
            if (RT_ERR_OK != rt_qos_schedulingQueue_get(pEntryData->dsQ.portId, &weights))
            {
                printk("%s(%d): Failed to call rt_qos_schedulingQueue_get\n", __FUNCTION__, __LINE__);
                continue;
            }

            if (pEntryData->dsQ.policy == PQ_POLICY_WEIGHTED_ROUND_ROBIN)
                weights.weights[pEntryData->dsQ.priority] = pEntryData->dsQ.weight;
            else
                weights.weights[pEntryData->dsQ.priority] = 0;
            OMCI_DRV_ERR_CHK(OMCI_LOG_LEVEL_ERR, rt_qos_schedulingQueue_set(pEntryData->dsQ.portId, &weights));
        }
    }

}



static int omci_SetDsPriQ(OMCI_PRIQ_ts *pPriQ)
{
    omci_UpdateDpMarkingByPriQId(pPriQ);
    return OMCI_ERR_OK;
}

static int pf_rt_SetPriQueue(OMCI_PRIQ_ts *pPriQ)
{
    rt_gpon_queueCfg_t queuecfg;

    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d dir:%d tcontId:%d q:%d\n",
        __FUNCTION__,__LINE__,pPriQ->dir,pPriQ->tcontId,pPriQ->queueId);
    
    if (PON_GEMPORT_DIRECTION_DS == pPriQ->dir)
        return omci_SetDsPriQ(pPriQ);


    memset(&queuecfg, 0, sizeof(queuecfg));
    queuecfg.weight         = pPriQ->weight;
    queuecfg.scheduleType   = pPriQ->scheduleType;
    queuecfg.pir            = pPriQ->pir == 0?RT_GPON_PON_QUEUE_PIR_UNLIMITED:pPriQ->pir;
    queuecfg.cir            = pPriQ->cir;


    if(RT_ERR_OK != rt_gpon_ponQueue_set(pPriQ->tcontId,pPriQ->queueId,&queuecfg))
    {

        if(pPriQ->queueId >= gPlatformDb.maxTcontQueue)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_WARN,"%s() %d PRI>=%d ignore\n",__FUNCTION__, __LINE__, gPlatformDb.maxTcontQueue);
            return OMCI_ERR_OK;
        }


        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d rt set upstream queue fail\n",__FUNCTION__,__LINE__);
        return OMCI_ERR_FAILED;
    }

    return OMCI_ERR_OK;
}


static int pf_rt_ClearPriQueue(OMCI_PRIQ_ts *pPriQ)
{  
    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s() %d dir:%d tcontId:%d q:%d\n",
        __FUNCTION__,__LINE__,pPriQ->dir,pPriQ->tcontId,pPriQ->queueId);

    if(RT_ERR_OK != rt_gpon_ponQueue_del(pPriQ->tcontId,pPriQ->queueId))
    {

        if(pPriQ->queueId >= gPlatformDb.maxTcontQueue){
            OMCI_LOG(OMCI_LOG_LEVEL_WARN,"%s() %d PRI>=%d ignore\n",__FUNCTION__, __LINE__, gPlatformDb.maxTcontQueue);
            return OMCI_ERR_OK;
        }

        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d rt del upstream queue fail\n",__FUNCTION__,__LINE__);
        return OMCI_ERR_FAILED;
    }

    return OMCI_ERR_OK;
}

static int pf_rt_DeactiveBdgConn(int servId)
{
    /*Delete MB entry*/
    if (OMCI_ERR_OK != pf_rt_DelMBcastRule(servId))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "del MBcast rule %u fail", servId);
    }

    /*Delete L2 entry*/
    if (OMCI_ERR_OK != pf_rt_DelL2Rule(servId))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "del L2 rule %u fail", servId);
    }

    /*Delete VEIP entry*/
    if (OMCI_ERR_OK != pf_rt_DelVeipRule(servId))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "del veip rule %u fail", servId);
    }

    return OMCI_ERR_OK;
}



/*Set L2 drop precedence*/
static int pf_rt_SetL2DpRule(OMCI_BRIDGE_RULE_ts *pBridgeRule, omci_dm_l2_info_t *pOrigDmL2Info)
{
    int32                     ret;
    omci_dm_l2_info_t       dmL2Info[2];
    flow2DsPq_entry_t       *pEntry = NULL;
    int pri;
    unsigned int usDrvDpFlowId,usDrvFlowId;
    BOOL bUsExtraRuleSet = FALSE; 
    BOOL bDsExtraRuleSet = FALSE; 
    
    if (!pBridgeRule || !pOrigDmL2Info)
        return OMCI_ERR_PARAM;

    /*index 0=> refer orignal rule,index 1=> new rule*/
    memcpy(&dmL2Info[0], pOrigDmL2Info, sizeof(omci_dm_l2_info_t));
    memset(&dmL2Info[1], 0x0, sizeof(omci_dm_l2_info_t));

    if(PON_GEMPORT_DIRECTION_US == pBridgeRule->dir || PON_GEMPORT_DIRECTION_BI == pBridgeRule->dir)
    {
        ret = omci_qos_GetUsDrvFlowId(pBridgeRule->usDpFlowId, &usDrvDpFlowId); 
        if(OMCI_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get drv flow id fail usDpFlowId:%d, ret:%d", 
                __FUNCTION__, __LINE__, pBridgeRule->usDpFlowId, ret);
            return OMCI_ERR_FAILED;
        }


        /*Check upstream */
        if(PQ_DROP_COLOUR_DEI_MARKING == pBridgeRule->usDpMarking)
        {
        
            /*DEI 0 uses orignal flowID(high queue)*/
            dmL2Info[0].usFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmL2Info[0].usFilterRule.innerTagDei   = 0;


            /*DEI 1 uses DP flowID(low queue)*/
            bUsExtraRuleSet    =   TRUE;
            memcpy(&dmL2Info[1].usFilterRule, &dmL2Info[0].usFilterRule, sizeof(omci_dm_filter_rule_t));
            memcpy(&dmL2Info[1].usOuterTagAct, &dmL2Info[0].usOuterTagAct, sizeof(omci_pon_wan_vlan_action_t));
            memcpy(&dmL2Info[1].usInnerTagAct, &dmL2Info[0].usInnerTagAct, sizeof(omci_pon_wan_vlan_action_t));
            dmL2Info[1].ingressPortMask = dmL2Info[0].ingressPortMask;
            dmL2Info[1].direction   = OMCI_RULE_DIR_ONLY_US;
            dmL2Info[1].usFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmL2Info[1].usFilterRule.innerTagDei   = 1;
            dmL2Info[1].flowId          = usDrvDpFlowId;
            dmL2Info[1].briIdx          = dmL2Info[0].briIdx;
        }
        else
        {
            if(pOrigDmL2Info->usFilterRule.filterMask & OMCI_DM_FILTER_INNER_PRI_BIT)
            {
                pri = pOrigDmL2Info->usFilterRule.innerTagPri;
                pf_rt_GetUsFlowdByDpMarkVal(pBridgeRule->usDpMarking, pOrigDmL2Info->flowId, usDrvDpFlowId, pri, &usDrvFlowId);
                dmL2Info[0].flowId          = usDrvFlowId;
                OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d flowId:%d ", __FUNCTION__, __LINE__,dmL2Info[0].flowId);
            }

        }
    }

    /*Check downstream*/
    if(PON_GEMPORT_DIRECTION_DS == pBridgeRule->dir || PON_GEMPORT_DIRECTION_BI == pBridgeRule->dir)
    {
        pEntry = flow2DsPq_entry_find(pBridgeRule->dsFlowId);

        if (!pEntry)
            goto SET_L2_INFO;

        if (0xFFFF == pEntry->dsQ.dsPqOmciPri)
            goto SET_L2_INFO;


        if(PQ_DROP_COLOUR_DEI_MARKING == pEntry->dsQ.dpMarking)
        {
            /*DEI 0 uses high queue*/
            dmL2Info[0].dsFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmL2Info[0].dsFilterRule.innerTagDei   = 0;
            dmL2Info[0].dsPriorityAct   =   OMCI_DM_DS_PRI_ACT_ASSIGN;
            dmL2Info[0].dsPriority      =   1;

            bDsExtraRuleSet    =   TRUE;
            memcpy(&dmL2Info[1].dsFilterRule, &dmL2Info[0].dsFilterRule, sizeof(omci_dm_filter_rule_t));
            memcpy(&dmL2Info[1].dsOuterTagAct, &dmL2Info[0].dsOuterTagAct, sizeof(omci_pon_wan_vlan_action_t));
            memcpy(&dmL2Info[1].dsInnerTagAct, &dmL2Info[0].dsInnerTagAct, sizeof(omci_pon_wan_vlan_action_t));
            dmL2Info[1].dsFilterRule.filterMask |= OMCI_DM_FILTER_INNER_DEI_BIT;
            dmL2Info[1].dsFilterRule.innerTagDei   = 1;
            dmL2Info[1].dsPriorityAct   =   OMCI_DM_DS_PRI_ACT_ASSIGN;
            dmL2Info[1].dsPriority      =   0;
            dmL2Info[1].ingressPortMask = dmL2Info[0].ingressPortMask;
            dmL2Info[1].briIdx          = dmL2Info[0].briIdx;

            if(TRUE == bUsExtraRuleSet)
                dmL2Info[1].direction   = OMCI_RULE_DIR_BOTH;
            else
                dmL2Info[1].direction   = OMCI_RULE_DIR_ONLY_DS;            


        }
        else
        {
            if(pOrigDmL2Info->dsFilterRule.filterMask & OMCI_DM_FILTER_INNER_PRI_BIT)
            {
                pri = pOrigDmL2Info->dsFilterRule.innerTagPri;
                pf_rt_GetDsPriActionByDpMarkVal(pEntry->dsQ.dpMarking, pri, &dmL2Info[0].dsPriorityAct, &dmL2Info[0].dsPriority);
            }

        }
    }

 SET_L2_INFO:

    dmL2Info[0].connectionId = TO_CONNECTION_ID(pBridgeRule->servId, 0);

#ifdef DM_DEBUG
    showDmL2Rule(&dmL2Info[0]);
#endif

    ret =  pDmmCb->omci_dm_l2_info_set(&dmL2Info[0]);
    if (RT_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d l2 dmm set fail ", __FUNCTION__, __LINE__);
    } 
    pf_rt_dm_AddL2Info(dmL2Info[0].connectionId);




    if(TRUE == bUsExtraRuleSet || TRUE == bDsExtraRuleSet)
    {
        dmL2Info[1].connectionId = TO_CONNECTION_ID(pBridgeRule->servId, 1);
#ifdef DM_DEBUG
        showDmL2Rule(&dmL2Info[1]);
#endif
        ret =  pDmmCb->omci_dm_l2_info_set(&dmL2Info[1]);
        if (RT_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d l2 dmm set fail ", __FUNCTION__, __LINE__);
        }
        pf_rt_dm_AddL2Info(dmL2Info[1].connectionId);
        

    }


    return OMCI_ERR_OK;

}

static int pf_rt_SetL2Rule(OMCI_BRIDGE_RULE_ts *pBridgeRule)
{
    int32                     ret;
    OMCI_VLAN_OPER_ts       *pVlanRule;
    l2_service_t            *pL2Entry;
    omci_dm_l2_info_t       dmL2Info;
    unsigned int            usDrvFlowId;
    OMCI_VLAN_ACT_ts        *pStagAct, *pCtagAct;
    int                     finalTag;
    BOOL                    bIsL2DpRule = FALSE;
    OMCI_VLAN_FILTER_ts     fakeDsfilter;
    BOOL isSkipSetDsRule = FALSE;
    BOOL isAddExtraDsRule = FALSE;
    int i =         0;
    macLimiterPort_entry_t          *macLimitGroup;


    if (NULL == pDmmCb || 
        NULL == pDmmCb->omci_dm_l2_info_set ||
        NULL == pDmmCb->omci_dm_l2_info_del)
    {

        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d l2 dmm callback is not registered", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    ret =  pf_rt_dm_DelL2InfoBySeverId(pBridgeRule->servId);
    if (OMCI_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "del dm l2 info fail, ret = %d", ret);
    }

    pVlanRule = &pBridgeRule->vlanRule;


    pL2Entry = l2Serv_entry_find(pBridgeRule->servId);

    if(!pL2Entry)
    {
        if((ret = l2Serv_entry_add(pBridgeRule))!=OMCI_ERR_OK)
        {
            return OMCI_ERR_FAILED;
        }

        pL2Entry = l2Serv_entry_find(pBridgeRule->servId);
        if(!pL2Entry)
        {
            return OMCI_ERR_FAILED;
        }
    }

    pL2Entry->usStreamId = pBridgeRule->usFlowId;
    pL2Entry->dsStreamId = pBridgeRule->dsFlowId;

    
    memset(&dmL2Info, 0, sizeof(dmL2Info));
    dmL2Info.connectionId = pBridgeRule->servId; 
    dmL2Info.briIdx = pBridgeRule->briId;

    switch(pBridgeRule->dir)
    {
        case PON_GEMPORT_DIRECTION_US:
            dmL2Info.direction = OMCI_RULE_DIR_ONLY_US;
            break;
        case PON_GEMPORT_DIRECTION_DS:
            dmL2Info.direction = OMCI_RULE_DIR_ONLY_DS;
            break;
        case PON_GEMPORT_DIRECTION_BI:
            dmL2Info.direction = OMCI_RULE_DIR_BOTH;
            break;
        default:
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, unknown direction %d", 
                __FUNCTION__, __LINE__, pBridgeRule->dir);
            return OMCI_ERR_FAILED;
            break;
    }

    ret = omci_qos_GetUsDrvFlowId(pBridgeRule->usFlowId, &usDrvFlowId);    

    if(OMCI_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get drv flow id fail usFlowId:%d, ret:%d", 
            __FUNCTION__, __LINE__, pBridgeRule->usFlowId, ret);
        return OMCI_ERR_FAILED;
    }

    dmL2Info.flowId = usDrvFlowId;

    dmL2Info.ingressPortMask = pBridgeRule->uniMask;

    if(OMCI_ERR_OK != pf_rt_dm_GetFilterRule(pVlanRule, &dmL2Info.usFilterRule))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get filter rule fail", __FUNCTION__, __LINE__);

    }

    pStagAct = &pVlanRule->sTagAct;
    pCtagAct = &pVlanRule->cTagAct;
    /*Stag/Ctag TRANSPARENT*/
    if(VLAN_ACT_TRANSPARENT == pStagAct->vlanAct && VLAN_ACT_TRANSPARENT == pCtagAct->vlanAct)
    {
        dmL2Info.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        dmL2Info.usInnerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
    }
    /*Stag TRANSPARENT*/
    else if(VLAN_ACT_TRANSPARENT == pStagAct->vlanAct && VLAN_ACT_TRANSPARENT != pCtagAct->vlanAct)
    {
        dmL2Info.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        if(pVlanRule->filterRule.filterStagMode == VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterStagMode == VLAN_FILTER_NO_TAG)
            finalTag=1;
        else
            finalTag=2;
        if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmL2Info.usInnerTagAct,finalTag,dmL2Info.usFilterRule.innerTagIf+dmL2Info.usFilterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

        }
        dmL2Info.usInnerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
    }
    /*Ctag TRANSPARENT*/
    else if(VLAN_ACT_TRANSPARENT != pStagAct->vlanAct && VLAN_ACT_TRANSPARENT == pCtagAct->vlanAct)
    {
        dmL2Info.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
        if(pVlanRule->filterRule.filterCtagMode == VLAN_FILTER_NO_CARE_TAG || pVlanRule->filterRule.filterCtagMode == VLAN_FILTER_NO_TAG)
            finalTag=1;
        else
            finalTag=2;
        if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmL2Info.usInnerTagAct,finalTag,dmL2Info.usFilterRule.innerTagIf+dmL2Info.usFilterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
        }
        pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmL2Info.usInnerTagAct.assignedTpid));
    }
    else
    {
        if(VLAN_ACT_REMOVE == pCtagAct->vlanAct && VLAN_ACT_REMOVE != pStagAct->vlanAct)
        {
            if(dmL2Info.usFilterRule.outerTagIf == 0)
            {
                dmL2Info.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            }
            else
            {
                dmL2Info.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_REMOVE;
            }
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmL2Info.usInnerTagAct,1,dmL2Info.usFilterRule.innerTagIf+dmL2Info.usFilterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
           pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmL2Info.usInnerTagAct.assignedTpid));
        }
        else if(VLAN_ACT_REMOVE != pCtagAct->vlanAct && VLAN_ACT_REMOVE == pStagAct->vlanAct)
        {
            dmL2Info.usOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmL2Info.usInnerTagAct,1,dmL2Info.usFilterRule.innerTagIf+dmL2Info.usFilterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }
           dmL2Info.usInnerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
        else
        {
            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->sTagAct, &dmL2Info.usOuterTagAct,2,dmL2Info.usFilterRule.innerTagIf+dmL2Info.usFilterRule.outerTagIf))
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);

            }

            pf_rt_dm_GetOutTpidMap(pVlanRule->outStyle.tpid,&(dmL2Info.usOuterTagAct.assignedTpid));

            if(OMCI_ERR_OK != pf_rt_dm_GetVlanTagAct(&pVlanRule->cTagAct, &dmL2Info.usInnerTagAct,1,dmL2Info.usFilterRule.innerTagIf+dmL2Info.usFilterRule.outerTagIf))
            {

                OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d fail", __FUNCTION__, __LINE__);
            }

            dmL2Info.usInnerTagAct.assignedTpid=OMCI_DEFAULT_CTAG_TPID;
        }
    }

    /*downstream*/
    if(pBridgeRule->dir != PON_GEMPORT_DIRECTION_US)
    {
        if(OMCI_ERR_OK != pf_rt_dm_GetDsFilterRule(pVlanRule, &dmL2Info.dsFilterRule))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get filter rule fail", __FUNCTION__, __LINE__);

        }
        dmL2Info.dsFilterRule.filterMask |= OMCI_DM_FILTER_FLOWID_BIT;
        dmL2Info.dsFilterRule.flowId = pBridgeRule->dsFlowId;
        if(OMCI_ERR_OK != pf_rt_dm_GetDsAction(pVlanRule, &dmL2Info.dsOuterTagAct, &dmL2Info.dsInnerTagAct,dmL2Info.dsFilterRule.innerTagIf+dmL2Info.dsFilterRule.outerTagIf))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get action fail", __FUNCTION__, __LINE__);

        }

        if(OMCI_ERR_OK != pf_rt_dm_GetDsPriAct(pBridgeRule, &dmL2Info.dsPriorityAct, &dmL2Info.dsPriority))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, get DsPriAct fail", __FUNCTION__, __LINE__);

        }

        
        if(OMCI_ERR_OK != pf_rt_UpdateRuleByExtVlanDsMode(pVlanRule, &dmL2Info.dsFilterRule, &dmL2Info.dsInnerTagAct, 
            &dmL2Info.dsOuterTagAct,&isSkipSetDsRule, &isAddExtraDsRule))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, extVlan dsMode fail", __FUNCTION__, __LINE__);

        }

        if(isSkipSetDsRule)
        {
            dmL2Info.direction = OMCI_RULE_DIR_ONLY_US;              
        }    
        

        /*Fake a vlan filter data to check is BDP 2 enable or not*/
        memset(&fakeDsfilter,0,sizeof(OMCI_VLAN_FILTER_ts));
        fakeDsfilter.filterStagMode = VLAN_FILTER_NO_TAG;
        fakeDsfilter.filterCtagMode = VLAN_FILTER_PRI;
        if (OMCIDRV_FEATURE_ERR_OK == omcidrv_feature_api(FEATURE_KAPI_BDP_00000002, &fakeDsfilter))
        {
            /*Ingore DS PBIT check*/
            dmL2Info.dsFilterRule.filterMask &= ~OMCI_DM_FILTER_INNER_PRI_BIT;
            dmL2Info.dsFilterRule.filterMask &= ~OMCI_DM_FILTER_OUTER_PRI_BIT;
        }
    }

    /* Configure per vlan per port mac learning limiter*/
    if(pBridgeRule->dir != PON_GEMPORT_DIRECTION_DS)
    {
        if( OMCIDRV_FEATURE_ERR_OK == omcidrv_feature_api(FEATURE_KAPI_BDP_00001000))
        {
            if(NULL != pDmmCb->omci_dm_l2_vlanGroupMacLimit_set)
            {
                for(i = gPlatformDb.allPortMin; i <= gPlatformDb.allPortMax; i++)
                {
                    if(pBridgeRule->uniMask & (1 << i))
                        macLimitGroup = macLimiterPort_entry_find(i, pBridgeRule->briId);
                    else
                        continue;
                    
                    if(macLimitGroup != NULL)
                    {
                        if (pBridgeRule->vlanRule.filterRule.filterCtagMode == VLAN_FILTER_NO_TAG && 
                            pBridgeRule->vlanRule.filterRule.filterStagMode == VLAN_FILTER_NO_TAG)
                        {
                            pDmmCb->omci_dm_l2_vlanGroupMacLimit_set(macLimitGroup->vlanGroupId, MACLIMITER_UNTAG, MACLIMITER_SET_VID);
                            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s,%d: TESTSTE", __FUNCTION__, __LINE__);
                        }
                        else
                            pDmmCb->omci_dm_l2_vlanGroupMacLimit_set(macLimitGroup->vlanGroupId, pBridgeRule->vlanRule.filterRule.filterCTag.vid, MACLIMITER_SET_VID);
                    }
                }
            }
        }
    }

    if(OMCI_ERR_OK != pf_rt_IsDpRule(pBridgeRule, &bIsL2DpRule))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d, check is L2 DP rule fail", __FUNCTION__, __LINE__);

    }


    if(TRUE == bIsL2DpRule)
    {
        return pf_rt_SetL2DpRule(pBridgeRule, &dmL2Info);
    }

#ifdef DM_DEBUG
    showDmL2Rule(&dmL2Info);
#endif

    ret =  pDmmCb->omci_dm_l2_info_set(&dmL2Info);
    if (RT_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,
            "add dm L2 info fail, ret = %d", ret);
    } 
    pf_rt_dm_AddL2Info(dmL2Info.connectionId);

    if(TRUE == isAddExtraDsRule)
    {
        if(0 ==pf_rt_dm_GetL2Info_DsDftCnt())
        {
            dmL2Info.dsFilterRule.filterMask = 0;
            dmL2Info.direction = OMCI_RULE_DIR_ONLY_DS;
            dmL2Info.connectionId = DS_DFT_CONNECTION_ID;
            dmL2Info.dsInnerTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;
            dmL2Info.dsOuterTagAct.tagAction = OMCI_PON_WAN_VLAN_TAGIF_TRANSPARENT;

            ret =  pDmmCb->omci_dm_l2_info_set(&dmL2Info);
            if (RT_ERR_OK != ret)
            {
                OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                    "add dm L2 info extra rule fail, ret = %d", ret);
            }
        }
        pf_rt_dm_AddL2DsDftRue(pBridgeRule->servId);


    }

    return OMCI_ERR_OK;
}

static int pf_rt_SetMBcastRule(OMCI_BRIDGE_RULE_ts *pBridgeRule)
{
    int ret = OMCI_ERR_OK;
    mbcast_service_t *pMBEntry;

    pMBEntry = mbcastServ_entry_find(pBridgeRule->servId);

    if(!pMBEntry)
    {
        // add entry
        if((ret = mbcastServ_entry_add(pBridgeRule->servId,
            &pBridgeRule->vlanRule, pBridgeRule->dsFlowId))!= OMCI_ERR_OK)
        {
            return OMCI_ERR_FAILED;
        }
        // get entry
        pMBEntry = mbcastServ_entry_find(pBridgeRule->servId);
        if(!pMBEntry)
        {
            return OMCI_ERR_FAILED;
        }
    }

    // invoke update not matter it's new or already exists
    if (OMCI_ERR_OK == (ret = pf_rt_updateMcastBcastRule(pMBEntry, pBridgeRule)))
    {
        pMBEntry->uniMask = pBridgeRule->uniMask;
        pMBEntry->isCfg = 1;
    }
    return ret;
}

static int pf_rt_ActiveBdgConn(OMCI_BRIDGE_RULE_ts *pBridgeRule)
{
    int ret = OMCI_ERR_OK;

    if(pBridgeRule == NULL)
    {
        return OMCI_ERR_OK;
    }

    if(PON_GEMPORT_DIRECTION_DS == pBridgeRule->dir)
    {
        ret = pf_rt_SetMBcastRule(pBridgeRule);
    }
    else
    {
        //exclude cpu port in l2 rule, it is for IP host connection and change to veip Rule
        if (pBridgeRule->uniMask & (~((1 << gPlatformDb.cpuPort) | (1 << gPlatformDb.ponPort))) && gDrvCtrl.devMode == OMCI_DEV_MODE_HYBRID)
        {
                ret = pf_rt_SetL2Rule(pBridgeRule);
        }
        else if (pBridgeRule->uniMask & (~(1 << gPlatformDb.ponPort)) && gDrvCtrl.devMode == OMCI_DEV_MODE_BRIDGE)
        {
                ret = pf_rt_SetL2Rule(pBridgeRule);
        }


        if((pBridgeRule->uniMask & (1 << gPlatformDb.ponPort)) &&  gDrvCtrl.devMode != OMCI_DEV_MODE_BRIDGE)
            ret = pf_rt_SetVeipRule(pBridgeRule);

        if((pBridgeRule->uniMask & (1 << gPlatformDb.cpuPort)) &&  gDrvCtrl.devMode != OMCI_DEV_MODE_BRIDGE)
        {
            OMCI_BRIDGE_RULE_ts newRule;
            
            if (OMCIDRV_FEATURE_ERR_OK != omcidrv_feature_api(FEATURE_KAPI_RDP_00000020, &newRule, pBridgeRule))
            {
                ret = omcidrv_IpHostToVeIpRule(&newRule, pBridgeRule);
            }
            ret = pf_rt_SetVeipRule(&newRule);
        }
    }

    return ret;

}

static int pf_rt_SetMSK(char *msk)
{
    rt_gpon_msk_t mskVal;

    if (!msk)
        return OMCI_ERR_FAILED;

    memcpy(&mskVal.mskData[0], msk,  RT_GPON_MSK_LEN);

    if (RT_ERR_OK != rt_gpon_msk_set(&mskVal))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d set msk fail\n", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }
  
    return OMCI_ERR_OK;
}

static int pf_rt_SetMcKey(omci_mc_key_info_t *pMcKey)
{
    rt_gpon_mc_key_t mcKeyVal;

    if (!pMcKey)
        return OMCI_ERR_PARAM;

    mcKeyVal.idx = pMcKey->idx;
    mcKeyVal.action = pMcKey->action;
    memcpy(&mcKeyVal.key[0], pMcKey->key,  RT_GPON_MCKEY_LEN);
    if (RT_ERR_OK != rt_gpon_mcKey_set(&mcKeyVal))
        return OMCI_ERR_FAILED;

    return OMCI_ERR_OK;
}

static int pf_rt_getPonTag(char *ponTag)
{
    rt_gpon_ponTag_t ponTagVal;

    if (!ponTag)
        return OMCI_ERR_FAILED;


    if (RT_ERR_OK != rt_gpon_ponTag_get(&ponTagVal))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d get pontag fail\n", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    memcpy(ponTag, &ponTagVal.tagData[0],  RT_GPON_PONTAG_LEN);
    
    return OMCI_ERR_OK;
}

static int pf_rt_SetOmciIk(char *omciIk)
{
    if (!omciIk)
        return RT_ERR_FAILED;

    memcpy(omci_ik, omciIk, OMCI_IK_LEN);

    return RT_ERR_OK;
}

static int pf_rt_SetSerialNum(char *serial)
{

    int32 ret;
    rt_gpon_serialNumber_t sn;
    
    sn.vendor[0] = serial[0];
    sn.vendor[1] = serial[1];
    sn.vendor[2] = serial[2];
    sn.vendor[3] = serial[3];
    sn.specific[0] = serial[4];
    sn.specific[1] = serial[5];
    sn.specific[2] = serial[6];
    sn.specific[3] = serial[7];
 
    if((ret = rt_gpon_serialNumber_set(&sn)) != RT_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Set GPON SN fail ret:%d\n", __FUNCTION__, __LINE__, ret);
        return OMCI_ERR_FAILED;
    }

    return RT_ERR_OK;
}

static int pf_rt_GetSerialNum(char *serial)
{
    return OMCI_ERR_OK;
}


static int pf_rt_SetGponPasswd(char *gponPwd)
{
    int32 ret;
    ret = rt_gpon_registrationId_set((rt_gpon_registrationId_t *)gponPwd);
    if(RT_ERR_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d set rgst ID fail\n",__FUNCTION__,__LINE__);
        return RT_ERR_FAILED;
    }

    return OMCI_ERR_OK;
}

static int pf_rt_ActivateGpon(omci_gpon_activate_cfg_t *pOnuActivateCfg)
{

    int32 ret = RT_ERR_OK;
    rt_gpon_initialState_t initState;

    if (!pOnuActivateCfg)
        return OMCI_ERR_PARAM;

    if(pOnuActivateCfg->activate)
    {
        initState = PON_ONU_STATE_EMERGENCY_STOP == pOnuActivateCfg->onuInitState ? RT_GPON_ONU_INIT_STATE_O7:RT_GPON_ONU_INIT_STATE_O1;
        if((ret = rt_gpon_activate(initState)) != RT_ERR_OK)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d activate GPON fail ret:%d\n", __FUNCTION__, __LINE__, ret);
            return OMCI_ERR_FAILED;
        }
    }
    else
    {
        if((ret = rt_gpon_deactivate()) != RT_ERR_OK)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d deactivate GPON fail ret:%d \n",__FUNCTION__,__LINE__, ret);
            return OMCI_ERR_FAILED;
        }
    }

    return OMCI_ERR_OK;
}

static int pf_rt_GetPonSpeed(omci_pon_speed_t *pSpeed)
{
    int ret;
    rt_ponmisc_ponMode_t ponMode;
    rt_ponmisc_ponSpeed_t ponSpeed;

    if((ret = rt_ponmisc_modeSpeed_get(&ponMode, &ponSpeed)) != RT_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d get pon speed  fail ret:%d\n", __FUNCTION__, __LINE__, ret);
        return OMCI_ERR_FAILED;
    }

    switch(ponSpeed)    
    {
        case RT_1G25G_SPEED:
            *pSpeed = OMCI_PON_SPEED_GPON;
            break;
        case RT_DN10G_SPEED:
            *pSpeed = OMCI_PON_SPEED_XGPON1;
            break;
        case RT_BOTH10G_SPEED:
            *pSpeed = OMCI_PON_SPEED_XGSPON;
            break;
        default:
            return OMCI_ERR_NOT_SUPPORT;
    }

    return OMCI_ERR_OK;
}


static int pf_rt_ResetMib(void)
{
    int i,ret;
    omci_dm_qos_dscp2pbit_t dscp2PbitTable;

//    rt_rate_storm_group_ctrl_t stormCtrl;

    // clear all ds flow queue info
    flow2DsPq_entry_delAll();

    /*Remove US/DS gem flow*/
    if(RT_ERR_OK != rt_gpon_dsFlow_delAll())
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Del all DS flow fail\n",__FUNCTION__,__LINE__);
    }

    if(RT_ERR_OK != omci_qos_usFlow_delAll())
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Del all US flow fail\n",__FUNCTION__,__LINE__);
    }

    if(OMCI_ERR_OK != _DelAllTcont())
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Del all Tcont fail\n",__FUNCTION__,__LINE__);
    }


    if(RT_ERR_OK != pf_rt_DelAllL2Rule())
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Del all L2 flow fail\n",__FUNCTION__,__LINE__);
    }
    

    if(RT_ERR_OK != pf_rt_DelAllVeipRule())
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Del all VEIP flow fail\n",__FUNCTION__,__LINE__);
    }


    if(RT_ERR_OK != pf_rt_DelAllMBcastRule())
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d Del all MBcast flow fail\n",__FUNCTION__,__LINE__);
    }


    /*Reset DSCP stable*/
    if (gDrvCtrl.dmMode && pDmmCb && pDmmCb->omci_dm_qos_dscp2pbit_set)
    {
        memset(&dscp2PbitTable, 0, sizeof(dscp2PbitTable));

        ret =  pDmmCb->omci_dm_qos_dscp2pbit_set(&dscp2PbitTable);
        if (RT_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                "%s()%d  set dm l2 dscp2pbit fail, ret = %d", 
                __FUNCTION__, __LINE__, ret);
        }

    }

    veipServ_entry_delAll();
    veipGemFlow_entry_delAll();
    for (i = 0; i < gPlatformDb.cfNum; i++)
    {
        /*remove hw cf rule*/
        if (!gPlatformDb.cfRule[i].isCfg)
            continue;

        //TBD, sync linux kernel protocol stack,
        //if (i <= gPlatformDb.veipFastStop)
            //rtk_rg_aclFilterAndQos_del(i);
        //else
            //rtk_rg_classifyEntry_del(i);

        /* reset sw cf rule */
        memset(&gPlatformDb.cfRule[i], 0, sizeof(pf_cf_rule_t));
    }
    ret = rtk_vlan_reservedVidAction_set(RESVID_ACTION_TAG, RESVID_ACTION_TAG);

    /*
    for(port = gPlatformDb.allPortMin; port <= gPlatformDb.allPortMax; port++)
        rtk_svlan_servicePort_set(port, DISABLED);
    ret = rtk_svlan_servicePort_set(gPlatformDb.ponPort, ENABLED);
    omci_cfg_vlan_table(0);*/

    // set default scheduler type to WRR TBD
//    rt_qos_schedulingType_set(RTK_QOS_WRR);


    // reset bandwidth
    for (i = gPlatformDb.etherPortMin; i <= gPlatformDb.etherPortMax; i++)
    {
        if(i == gPlatformDb.ponPort || i == gPlatformDb.rgmiiPort)
            continue;
        rt_rate_portEgrBandwidthCtrlRate_set(i, gPlatformDb.maxBwRate);
        rt_rate_portIgrBandwidthCtrlRate_set(i, gPlatformDb.maxBwRate);
    }

#if 0 /*TBD storm control /meter direclty use RT API(*/
    for (i = 0; i < gPlatformDb.meterNum; i++)
    {
        if (gPlatformDb.rsvMeterId == i)
            continue;
        if (!gPlatformDb.stormCtrl[i].isCfg)
            continue;

        // disable storm control
        OMCI_DRV_ERR_CHK(OMCI_LOG_LEVEL_ERR, rt_rate_stormControlEnable_get(&stormCtrl));
        stormCtrl.unknown_unicast_enable = DISABLED;
        stormCtrl.broadcast_enable = DISABLED;
        stormCtrl.multicast_enable = DISABLED;
        OMCI_DRV_ERR_CHK(OMCI_LOG_LEVEL_ERR, rt_rate_stormControlEnable_set(&stormCtrl));

        // disable meters
        rt_rate_shareMeter_set(gPlatformDb.stormCtrl[i].meterIdx, 0, DISABLED);

        memset(&gPlatformDb.stormCtrl[i], 0, sizeof(pf_stormCtrl_t));
    }
#endif
    return OMCI_ERR_OK;
}

static int pf_rt_DumpL2Serv(void)
{
    struct list_head *next,*tmp;
    omci_connection_info_t *cur;

    printk("L2 Conn-ID to dmm\r\n");
    printk("-----------------\r\n");
    list_for_each_safe(next, tmp, &gL2FlowHead){

        cur = list_entry(next, omci_connection_info_t, list);       
        printk("0x%x\r\n", cur->connectionId);
    }

    printk("\r\nL2 Conn-ID with DS default rule\r\n");
    printk("-----------------------------------\r\n");
    list_for_each_safe(next, tmp, &gL2DsDftHead){

        cur = list_entry(next, omci_connection_info_t, list);       
        printk("0x%x\r\n", cur->connectionId);
    }
    
    return OMCI_ERR_OK;
}


static int pf_rt_DumpVeipServ(void)
{
    struct list_head *next,*tmp;
    omci_connection_info_t *cur;

    printk("Veip Conn-ID\r\n");
    printk("--------\r\n");
    list_for_each_safe(next, tmp, &gVeipFlowHead){

        cur = list_entry(next, omci_connection_info_t, list);       
        printk("0x%x\r\n", cur->connectionId);
    }

    printk("\r\nVeip Conn-ID with DS default rule\r\n");
    printk("-----------------------------------\r\n");
    list_for_each_safe(next, tmp, &gVeipDsDftHead){

        cur = list_entry(next, omci_connection_info_t, list);       
        printk("0x%x\r\n", cur->connectionId);
    }         
    return OMCI_ERR_OK;
}

static int pf_rt_DumpMBServ(void)
{
    struct list_head *next,*tmp;
    mbcast_service_t *cur;

    int ret = OMCI_ERR_OK;

    printk("Conn-ID    DsFlowID   uniMask\r\n");
    printk("------------------------------------\r\n");
    list_for_each_safe(next, tmp, &gPlatformDb.mbcastHead){

        cur = list_entry(next, mbcast_service_t, list);       
        printk("%-10d  %-10d  0x%-8x\r\n", 
            cur->index, cur->dsStreamId, cur->uniMask);
    }

    return ret;
}





static int pf_rt_ExitPlatform(void)
{
    //rtk_gpon_deActivate();
    omci_exit();
    //rtk_gponapp_evtHdlPloam_dreg();
    return 0;
}

static int pf_rt_SetDscpRemap(OMCI_DSCP2PBIT_ts *pDscp2PbitTable)
{
    int ret = RT_ERR_OK;
    omci_dm_qos_dscp2pbit_t dscp2PbitTable;
    int i;

    OMCI_LOG(OMCI_LOG_LEVEL_INFO,"%s %d : DSCP2P-bit",__FUNCTION__,__LINE__);
    if (gDrvCtrl.logLevel >= OMCI_LOG_LEVEL_INFO)
        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 8, 1, pDscp2PbitTable, 64, true);

    if (gDrvCtrl.dmMode && (!pDmmCb || !pDmmCb->omci_dm_qos_dscp2pbit_set))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s()%d dmm callback is not registered", __FUNCTION__, __LINE__);

        return OMCI_ERR_FAILED;
    }


    if (gDrvCtrl.dmMode)
    {

        for(i=0;i<OMCI_DSCP_NUM;i++)
            dscp2PbitTable.dscp[i] = pDscp2PbitTable->pbit[i];

        ret =  pDmmCb->omci_dm_qos_dscp2pbit_set(&dscp2PbitTable);
        if (RT_ERR_OK != ret)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,
                "set dm l2 dscp2pbit fail, ret = %d", ret);
        }

    }

    return ret;
}

static int pf_rt_SetMacLearnLimit(OMCI_MACLIMIT_ts *pMacLimit)
{
    int                             vlanGroupId;
    macLimiterPort_entry_t          *macLimitGroup;
    BOOL                            isCreate;
    rt_switch_devInfo_t             tDevInfo;

    // only apply mac limiter here if enable per port per vlan mac limier
    if( OMCIDRV_FEATURE_ERR_OK != omcidrv_feature_api(FEATURE_KAPI_BDP_00001000))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "just apply mac limiter to tr142");
        return 0;
    }

    if (!pMacLimit)
    {
        return RT_ERR_FAILED;
    }

    if (RT_ERR_OK != rt_switch_deviceInfo_get(&tDevInfo))
    {
        return RT_ERR_FAILED;
    }

    if (NULL == pDmmCb ||
        NULL == pDmmCb->omci_dm_l2_vlanGroupMacLimit_add ||
        NULL == pDmmCb->omci_dm_l2_vlanGroupMacLimit_set ||
        NULL == pDmmCb->omci_dm_l2_vlanGroupMacLimit_del)
    {

        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "%s:%d l2 dmm vlanGroupMacLimiter callback is not registered", __FUNCTION__, __LINE__);
        return OMCI_ERR_FAILED;
    }

    if(tDevInfo.capacityInfo.l2_learn_limit_cnt_max == pMacLimit->macLimitNum)
        isCreate = FALSE;
    else
        isCreate = TRUE;

    if(isCreate)
    {
        macLimitGroup = macLimiterPort_entry_find(pMacLimit->portIdx, pMacLimit->briIdx);
        if(macLimitGroup == NULL)
        {
            pDmmCb->omci_dm_l2_vlanGroupMacLimit_add(pMacLimit->portIdx, pMacLimit->macLimitNum, &vlanGroupId);
            macLimiterPort_entry_add(pMacLimit->portIdx, pMacLimit->briIdx, vlanGroupId);
            printk( "pMacLimit %d, %d, %d\n", pMacLimit->portIdx, pMacLimit->briIdx, vlanGroupId);
        }
        else
        {
            pDmmCb->omci_dm_l2_vlanGroupMacLimit_set(macLimitGroup->vlanGroupId, MACLIMITER_SET_LIMIT, pMacLimit->macLimitNum);
        }
    }
    else
    {
        if(pMacLimit->briIdx == -1)
        {
            //for mib reset
            macLimitGroup = macLimiterPort_entry_findByPort(pMacLimit->portIdx);
            while(macLimitGroup  != NULL)
            {
                pDmmCb->omci_dm_l2_vlanGroupMacLimit_del(macLimitGroup->vlanGroupId,MACLIMITER_DEL_GROUP);
                printk( "pMacLimit %d, %d, %d\n", macLimitGroup->portId, macLimitGroup->briId, macLimitGroup->vlanGroupId);
                macLimiterPort_entry_del(macLimitGroup->portId, macLimitGroup->briId);
                macLimitGroup = macLimiterPort_entry_findByPort(pMacLimit->portIdx);
            }
        }
        else
        {
            macLimitGroup = macLimiterPort_entry_find(pMacLimit->portIdx, pMacLimit->briIdx);
            if(macLimitGroup != NULL)
            {
                pDmmCb->omci_dm_l2_vlanGroupMacLimit_del(macLimitGroup->vlanGroupId,MACLIMITER_DEL_GROUP);
                macLimiterPort_entry_del(pMacLimit->portIdx, pMacLimit->briIdx);
            }
        }
    }
    
    return 0;
}

static int pf_rt_SetMacFilter(OMCI_MACFILTER_ts *pMacFilter)
{
    #if 0
    /*TBD*/
    #endif
    return 0;
}


static int pf_rt_GetDevCapabilities(omci_dev_capability_t *p)
{
    rt_switch_devInfo_t    tDevInfo;
    uint8                   portId;
    uint32                  r;
    uint8                   totalUniPort = 0;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_switch_deviceInfo_get(&tDevInfo))
        return RT_ERR_FAILED;

    memset(p->ethPort, 0, sizeof(omci_eth_port_t) * RTK_MAX_NUM_OF_PORTS);
    p->fePortNum = 0;
    p->gePortNum = 0;
    p->cpuPort = -1;
    p->rgmiiPort = -1;
    p->ponPort = -1;
    p->potsPortNum = 0;
    p->totalTContNum = 0;
    p->totalGEMPortNum = 0;
    p->totalTContQueueNum = 0;
    p->perUNIQueueNum = 0;
    p->meterNum = 0;

    // learn non-UNI ports info
    p->cpuPort = tDevInfo.cpuPort;
    p->rgmiiPort = tDevInfo.rgmiiPort;
    p->ponPort = tDevInfo.ponPort;


    // learn UNI ports info
    for (portId = 0; portId < RTK_MAX_NUM_OF_PORTS; portId++)
    {
        if ((1 << portId) & tDevInfo.fe.portmask.bits[0])
        {
            if (portId != p->cpuPort &&
                    portId != p->rgmiiPort &&
                    portId != p->ponPort)
            {
                p->ethPort[portId].portType = OMCI_ETH_PORT_FE;
                p->ethPort[portId].portIdInType = p->fePortNum++;
                totalUniPort++;
            }
        }

        if ((1 << portId) & tDevInfo.ge.portmask.bits[0])
        {
            if (portId != p->cpuPort &&
                    portId != p->rgmiiPort &&
                    portId != p->ponPort)
            {
                p->ethPort[portId].portType = OMCI_ETH_PORT_GE;
#ifdef KAON_CUSTOMER_SKB
                p->gePortNum++;
                p->ethPort[portId].portIdInType = (4 - p->gePortNum);
#else
                p->ethPort[portId].portIdInType = p->gePortNum++;
#endif
                totalUniPort++;
            }
        }
    }

    get_resouce_by_dev_feature(DEV_FEATURE_ALL, p);
    get_resouce_by_dev_feature(DEV_FEATURE_ETH, p);
    totalUniPort = p->fePortNum + p->gePortNum + p->eth2p5gPortNum + p->xePortNum;
    OMCI_LOG(OMCI_LOG_LEVEL_INFO, "%s UNI num:%d", __FUNCTION__, totalUniPort);

    if (OMCIDRV_FEATURE_ERR_FAIL == omcidrv_feature_api(FEATURE_KAPI_ME_00020000, (int32)-1, (uint32)0, p, &totalUniPort))
    {
        r = (OMCIDRV_FEATURE_ERR_OK ==
                omcidrv_feature_api(FEATURE_KAPI_ME_00000200)) ? TRUE : FALSE;
        omcidrv_feature_api(FEATURE_KAPI_ME_00000001, r, p);
    }


    // learn other capabilities
    p->totalTContNum        = gPlatformDb.maxTcont;
    p->totalTContQueueNum   = gPlatformDb.maxPonQueue;

    if( OMCIDRV_FEATURE_ERR_OK == omcidrv_feature_api(FEATURE_KAPI_ME_00100000, p))
    {
        p->totalTContQueueNum = p->totalTContNum*8;
        OMCI_LOG(OMCI_LOG_LEVEL_INFO, "%s T-CONT num:%d", __FUNCTION__, p->totalTContNum);
    }

    p->totalGEMPortNum      = gPlatformDb.maxFlow;
    p->perUNIQueueNum       = gPlatformDb.perUniQueue;
    p->meterNum             = gPlatformDb.meterNum;
    p->rsvMeterId           = gPlatformDb.rsvMeterId;
    p->totalL2Num           = tDevInfo.capacityInfo.l2_learn_limit_cnt_max;

//    get_resouce_by_dev_feature(DEV_FEATURE_ALL, p);
//    get_resouce_by_dev_feature(DEV_FEATURE_ETH, p);

    return RT_ERR_OK;
}

static int pf_rt_GetDevIdVersion(omci_dev_id_version_t *p)
{
    uint32  chipId = 0;
    uint32  rev = 0;
    uint32  subType = 0;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_switch_version_get(&chipId, &rev, &subType))
        return RT_ERR_FAILED;

    memset(p->id, 0, OMCI_DRV_DEV_ID_LEN);
    memset(p->version, 0, OMCI_DRV_DEV_VERSION_LEN);

    p->chipId = chipId;

    // learn device id and its version
    switch (chipId)
    {
        case APOLLOMP_CHIP_ID:
        {
            switch (subType)
            {
                case 0x03:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9601");
                    break;
                case 0x07:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL86906");
                    break;
                case 0x09:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9606");
                    break;
                case 0x0b:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9607");
                    break;
                case 0x0d:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9602");
                    break;
                case 0x0f:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9603");
                    break;
                case 0x13:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL8696");
                    break;
                case 0x17:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL8198B");
                    break;
                default:
                    snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "Unknown");
                    break;
            }
            break;
        }
        case RTL9601B_CHIP_ID:
            snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9601B");
            break;
        case RTL9602C_CHIP_ID:
            snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9602C");
            break;
        case RTL9607C_CHIP_ID:
            snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "RTL9607C");
            break;
        case LUNA_G3_CHIP_ID:
            snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "LUNA_G3");
            break;  
        case CA8279_CHIP_ID:
            snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "CA8277");
            break;
        default:
            snprintf(p->id, OMCI_DRV_DEV_ID_LEN, "Unknown");
            break;
    }
    snprintf(p->version, OMCI_DRV_DEV_VERSION_LEN, "%u", rev);

    return RT_ERR_OK;
}

static int pf_rt_GetUsDBRuStatus(unsigned int *p)
{
    rt_gpon_attribute_t attributeValue;
    memset(&attributeValue,0,sizeof(rt_gpon_attribute_t));
    if(rt_gpon_attribute_get(RT_GPON_ATTRIBUTE_TYPE_DBRU_STATUS,&attributeValue) != RT_ERR_OK)
    {
        *p = 0;
        return RT_ERR_FAILED;
    }
    *p = attributeValue.dbruStatus;
    return RT_ERR_OK;
}

static int pf_rt_GetOnuRspTime(unsigned int *p)
{
    rt_gpon_attribute_t attributeValue;
    memset(&attributeValue,0,sizeof(rt_gpon_attribute_t));
    if(rt_gpon_attribute_get(RT_GPON_ATTRIBUTE_TYPE_GTC_INFO,&attributeValue) != RT_ERR_OK)
    {
        *p = 0;
        return RT_ERR_FAILED;
    }
    *p = attributeValue.gtc_info.responTime;
    return RT_ERR_OK;
}

static int pf_rt_GetTransceiverStatus(omci_transceiver_status_t *p)
{
    rt_transceiver_parameter_type_t type;
    rt_transceiver_data_t data;

    int ret;

    if (!p)
        return OMCI_ERR_PARAM;

    switch (p->type)
    {
        case OMCI_TRANSCEIVER_STATUS_TYPE_VENDOR_NAME:
            type = RT_TRANSCEIVER_PARA_TYPE_VENDOR_NAME;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_VENDOR_PART_NUM:
            type = RT_TRANSCEIVER_PARA_TYPE_VENDOR_PART_NUM;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_VENDOR_SN:
            type = RT_TRANSCEIVER_PARA_TYPE_SN;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_TEMPERATURE:
            type = RT_TRANSCEIVER_PARA_TYPE_TEMPERATURE;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_VOLTAGE:
            type = RT_TRANSCEIVER_PARA_TYPE_VOLTAGE;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_BIAS_CURRENT:
            type = RT_TRANSCEIVER_PARA_TYPE_BIAS_CURRENT;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_TX_POWER:
            type = RT_TRANSCEIVER_PARA_TYPE_TX_POWER;
            break;
        case OMCI_TRANSCEIVER_STATUS_TYPE_RX_POWER:
            type = RT_TRANSCEIVER_PARA_TYPE_RX_POWER;
            break;
        default:
            return OMCI_ERR_PARAM;
            break;
    }    
 
    ret = rt_ponmisc_transceiver_get(type, &data);
    if(RT_ERR_OK!= ret)
        return RT_ERR_FAILED;

   if (sizeof(data.buf) < sizeof(p->data))
       memcpy(p->data, data.buf, sizeof(data.buf));
   else
       memcpy(p->data, data.buf, sizeof(p->data));

;


    

    return OMCI_ERR_OK;
}

static int pf_rt_GetPortLinkStatus(omci_port_link_status_t *p)
{
    rt_port_linkStatus_t   linkStatus;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_link_get(p->port, &linkStatus))
        return RT_ERR_FAILED;

    p->status = (RT_PORT_LINKUP == linkStatus) ? TRUE : FALSE;

    return RT_ERR_OK;
}

static int pf_rt_GetPortSpeedDuplexStatus(omci_port_speed_duplex_status_t *p)
{
    rt_port_speed_t    speed;
    rt_port_duplex_t   duplex;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_speedDuplex_get(p->port, &speed, &duplex))
        return RT_ERR_FAILED;

    switch (speed)
    {
        case PORT_SPEED_10M:
            p->speed = OMCI_PORT_SPEED_10M;
            break;
        case PORT_SPEED_100M:
            p->speed = OMCI_PORT_SPEED_100M;
            break;
        case PORT_SPEED_1000M:
            p->speed = OMCI_PORT_SPEED_1000M;
            break;
        case PORT_SPEED_10G:
            p->speed = OMCI_PORT_SPEED_10G;
            break;
        case RT_PORT_SPEED_2G5:
            p->speed = OMCI_PORT_SPEED_2DOT5G;
            break;    
        default:
            return RT_ERR_FAILED;
            break;
    }

    switch (duplex)
    {
        case PORT_HALF_DUPLEX:
            p->duplex = OMCI_PORT_HALF_DUPLEX;
            break;
        case PORT_FULL_DUPLEX:
            p->duplex = OMCI_PORT_FULL_DUPLEX;
            break;
        default:
            return RT_ERR_FAILED;
            break;
    }

    return RT_ERR_OK;
}

static int pf_rt_SetPortAutoNegoAbility(omci_port_auto_nego_ability_t *p)
{
     rt_port_phy_ability_t  phyAbility;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyAutoNegoAbility_get(p->port, &phyAbility))
        return RT_ERR_FAILED;


    if(phyAbility.Full_10 == p->full_10 &&
        phyAbility.Half_10 == p->half_10 &&
        phyAbility.Full_100 == p->full_100 &&      
        phyAbility.Half_100 == p->half_100 &&
        phyAbility.Full_1000 == p->full_1000 &&
        phyAbility.Full_2500 == p->full_2500 &&
        phyAbility.Full_10000 == p->full_10000
        )
    {
        OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s due to same config, skip setting port[%u]", __FUNCTION__, p->port);
        return RT_ERR_OK;
    }

    phyAbility.Full_10 = p->full_10;
    phyAbility.Half_10 = p->half_10;
    phyAbility.Full_100 = p->full_100;
    phyAbility.Half_100 = p->half_100;
    phyAbility.Full_1000 = p->full_1000;
    phyAbility.Half_1000 = p->half_1000;
    phyAbility.Full_2500 = p->full_2500;
    phyAbility.Full_10000 = p->full_10000;

    if (RT_ERR_OK != rt_port_phyAutoNegoAbility_set(p->port, &phyAbility))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_GetPortAutoNegoAbility(omci_port_auto_nego_ability_t *p)
{
    rt_port_phy_ability_t  phyAbility;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyAutoNegoAbility_get(p->port, &phyAbility))
        return RT_ERR_FAILED;

    p->full_10 = phyAbility.Full_10;
    p->half_10 = phyAbility.Half_10;
    p->full_100 = phyAbility.Full_100;
    p->half_100 = phyAbility.Half_100;
    p->full_1000 = phyAbility.Full_1000;
    p->half_1000 = phyAbility.Half_1000;

    return RT_ERR_OK;

}

static int pf_rt_SetPortState(omci_port_state_t *p)
{
    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_adminEnable_set(p->port, p->state))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_GetPortState(omci_port_state_t *p)
{
    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_adminEnable_get(p->port, &p->state))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_SetPortMaxFrameSize(omci_port_max_frame_size_t *p)
{
    if (!p)
        return RT_ERR_FAILED;
    // TBD
    // mtu modification is not supported
    // mtu is shared with cpu port,it need consider RTK/8277 chip
    // hence cpu tag and vlan tag has to be considered


    return RT_ERR_OK;
}

static int pf_rt_GetPortMaxFrameSize(omci_port_max_frame_size_t *p)
{
    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_switch_maxPktLenByPort_get(p->port, &p->size))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_SetPortPhyLoopback(omci_port_loopback_t *p)
{
    uint32  data;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyReg_get(p->port, PHY_PAGE_0, PHY_CONTROL_REG, &data))
        return RT_ERR_FAILED;

    if (p->loopback)
        data |= Loopback_MASK;
    else
        data &= ~Loopback_MASK;

    if (RT_ERR_OK != rt_port_phyReg_set(p->port, PHY_PAGE_0, PHY_CONTROL_REG, data))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_GetPortPhyLoopback(omci_port_loopback_t *p)
{
    uint32  data;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyReg_get(p->port, PHY_PAGE_0, PHY_CONTROL_REG, &data))
        return RT_ERR_FAILED;

    if (data & Loopback_MASK)
        p->loopback = TRUE;
    else
        p->loopback = FALSE;

    return RT_ERR_OK;
}

static int pf_rt_SetPortPhyPwrDown(omci_port_pwr_down_t *p)
{
    uint32  data;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyReg_get(p->port, PHY_PAGE_0, PHY_CONTROL_REG, &data))
        return RT_ERR_FAILED;

    if (p->state)
        data |= PowerDown_MASK;
    else
        data &= ~PowerDown_MASK;

    if (RT_ERR_OK != rt_port_phyReg_set(p->port, PHY_PAGE_0, PHY_CONTROL_REG, data))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_GetPortPhyPwrDown(omci_port_pwr_down_t *p)
{
    uint32  data;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyReg_get(p->port, PHY_PAGE_0, PHY_CONTROL_REG, &data))
        return RT_ERR_FAILED;

    if (data & PowerDown_MASK)
        p->state = TRUE;
    else
        p->state = FALSE;

    return RT_ERR_OK;
}

static int pf_rt_GetPortStat(omci_port_stat_t *p)
{
    rt_stat_port_cntr_t    portCntrs;

    if (!p)
        return OMCI_ERR_PARAM;

    if (RT_ERR_OK != rt_stat_port_getAll(p->port, &portCntrs))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d  fail !!",__FUNCTION__,__LINE__); 
        return OMCI_ERR_FAILED;
    }
    p->ifInOctets                       = portCntrs.ifInOctets;
    p->ifInUcastPkts                    = portCntrs.ifInUcastPkts;
    p->ifInMulticastPkts                = portCntrs.ifInMulticastPkts;
    p->ifInBroadcastPkts                = portCntrs.ifInBroadcastPkts;
    p->ifInDiscards                     = portCntrs.ifInDiscards;
    p->ifOutOctets                      = portCntrs.ifOutOctets;
    p->ifOutUcastPkts                   = portCntrs.ifOutUcastPkts;
    p->ifOutMulticastPkts               = portCntrs.ifOutMulticastPkts;
    p->ifOutBrocastPkts                 = portCntrs.ifOutBrocastPkts;
    p->ifOutDiscards                    = portCntrs.ifOutDiscards;
    p->dot1dTpPortInDiscards            = portCntrs.dot1dTpPortInDiscards;
    p->dot3StatsSingleCollisionFrames   = portCntrs.dot3StatsSingleCollisionFrames;
    p->dot3StatsMultipleCollisionFrames = portCntrs.dot3StatsMultipleCollisionFrames;
    p->dot3StatsDeferredTransmissions   = portCntrs.dot3StatsDeferredTransmissions;
    p->dot3StatsLateCollisions          = portCntrs.dot3StatsLateCollisions;
    p->dot3StatsExcessiveCollisions     = portCntrs.dot3StatsExcessiveCollisions;
    p->dot3InPauseFrames                = portCntrs.dot3InPauseFrames;
    p->dot3OutPauseFrames               = portCntrs.dot3OutPauseFrames;
    p->dot3StatsAligmentErrors          = portCntrs.dot3StatsAligmentErrors;
    p->dot3StatsFCSErrors               = portCntrs.dot3StatsFCSErrors;
    p->dot3StatsSymbolErrors            = portCntrs.dot3StatsSymbolErrors;
    p->dot3StatsFrameTooLongs           = portCntrs.dot3StatsFrameTooLongs;
    p->etherStatsDropEvents             = portCntrs.etherStatsDropEvents;
    p->etherStatsFragments              = portCntrs.etherStatsFragments;
    p->etherStatsJabbers                = portCntrs.etherStatsJabbers;
    p->etherStatsCRCAlignErrors         = portCntrs.etherStatsCRCAlignErrors;
    p->etherStatsTxUndersizePkts        = portCntrs.etherStatsTxUndersizePkts;
    p->etherStatsTxOversizePkts         = portCntrs.etherStatsTxOversizePkts;
    p->etherStatsTxPkts64Octets         = portCntrs.etherStatsTxPkts64Octets;
    p->etherStatsTxPkts65to127Octets    = portCntrs.etherStatsTxPkts65to127Octets;
    p->etherStatsTxPkts128to255Octets   = portCntrs.etherStatsTxPkts128to255Octets;
    p->etherStatsTxPkts256to511Octets   = portCntrs.etherStatsTxPkts256to511Octets;
    p->etherStatsTxPkts512to1023Octets  = portCntrs.etherStatsTxPkts512to1023Octets;
    p->etherStatsTxPkts1024to1518Octets = portCntrs.etherStatsTxPkts1024to1518Octets;
    p->etherStatsTxPkts1519toMaxOctets  = portCntrs.etherStatsTxPkts1519toMaxOctets;
    p->etherStatsTxCRCAlignErrors       = portCntrs.etherStatsTxCRCAlignErrors;
    p->etherStatsRxUndersizePkts        = portCntrs.etherStatsRxUndersizePkts;
    p->etherStatsRxOversizePkts         = portCntrs.etherStatsRxOversizePkts;
    p->etherStatsRxPkts64Octets         = portCntrs.etherStatsRxPkts64Octets;
    p->etherStatsRxPkts65to127Octets    = portCntrs.etherStatsRxPkts65to127Octets;
    p->etherStatsRxPkts128to255Octets   = portCntrs.etherStatsRxPkts128to255Octets;
    p->etherStatsRxPkts256to511Octets   = portCntrs.etherStatsRxPkts256to511Octets;
    p->etherStatsRxPkts512to1023Octets  = portCntrs.etherStatsRxPkts512to1023Octets;
    p->etherStatsRxPkts1024to1518Octets = portCntrs.etherStatsRxPkts1024to1518Octets;
    p->etherStatsRxPkts1519toMaxOctets  = portCntrs.etherStatsRxPkts1519toMaxOctets;

    return OMCI_ERR_OK;
}

static int pf_rt_ResetPortStat(unsigned int port)
{
    if (RT_ERR_OK != rt_stat_port_reset(port))
        return RT_ERR_FAILED;
    return RT_ERR_OK;
}

static int pf_rt_GetUsFlowStat(omci_flow_stat_t *p)
{
    rt_gpon_flow_counter_t     flowCntrs;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_gpon_flowCounter_get(p->flow, RT_GPON_CNT_TYPE_FLOW_US_GEM, &flowCntrs))
        return RT_ERR_FAILED;

    p->gemBlock = flowCntrs.usgem.gem_block;
    p->gemByte = flowCntrs.usgem.gem_byte;

    return RT_ERR_OK;
}

static int pf_rt_ResetUsFlowStat(unsigned int flow)
{
    return RT_ERR_OK;
}

static int pf_rt_GetDsFlowStat(omci_flow_stat_t *p)
{

    rt_gpon_flow_counter_t     flowCntrs;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_gpon_flowCounter_get(p->flow, RT_GPON_CNT_TYPE_FLOW_DS_GEM, &flowCntrs))
        return RT_ERR_FAILED;

    p->gemBlock = flowCntrs.dsgem.gem_block;
    p->gemByte = flowCntrs.dsgem.gem_byte;

    return RT_ERR_OK;
}

static int pf_rt_ResetDsFlowStat(unsigned int flow)
{
    return RT_ERR_OK;
}

static int pf_rt_GetDsFecStat(omci_ds_fec_stat_t *p)
{
#if 0
    ca_status_t ret = CA_E_OK;
    ca_gpon_port_fec_stat_t fec_stat;

    if (!p)
        return RT_ERR_FAILED;

    if((ret = ca_gpon_port_fec_stat_get(0,0,1,&fec_stat)) != CA_E_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : ca_gpon_port_fec_stat_get Error!!",__FUNCTION__,__LINE__);
        return RT_ERR_FAILED;
    }

    p->corByte = fec_stat.corrected_bytes;    /* The number of bytes that were corrected by the FEC */
    p->corCodeword = fec_stat.corrected_codewords;    /* The codewords that were corrected by the FEC */
    p->uncorCodeword = fec_stat.uncorrectable_codewords;    /* Error codewords that could not be corrected by the FEC */
#endif
    return RT_ERR_OK;
}

static int pf_rt_ResetDsFecStat(void)
{
#if 0
    ca_status_t ret = CA_E_OK;
    ca_gpon_port_fec_stat_t fec_stat;

    if((ret = ca_gpon_port_fec_stat_get(0,0,0,&fec_stat)) != CA_E_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_DRIVER,"%s %d : ca_gpon_port_fec_stat_get Error!!",__FUNCTION__,__LINE__);
        return RT_ERR_FAILED;
    }
#endif
    return RT_ERR_OK;
}

static int pf_rt_SetExtEthPmFilter(omci_ext_eth_pm_filter_t *filter)
{
    rt_stat_gemFilter_conf_t gemFilter;
    memset(&gemFilter,0,sizeof(rt_stat_gemFilter_conf_t));
    gemFilter.enable = ENABLED;
    if(filter->type == OMCI_EXT_ETH_PM_TYPE_FLOW)
    {
        gemFilter.type = RT_STAT_FILTER_FLOW;
        gemFilter.type_flowId = filter->portId;
    }
    else
    {
        gemFilter.type = RT_STAT_FILTER_PORT;
        gemFilter.type_portId = filter->portId;
    }
    if(filter->vid == 0xffff)
        gemFilter.filter_vid = RT_STAT_GEMMIB_FILTER_VID_INVAILD;
    else
        gemFilter.filter_vid = filter->vid;

    if(filter->pri == 8)
        gemFilter.filter_pri = RT_STAT_GEMMIB_FILTER_PRI_INVAILD;
    else
        gemFilter.filter_pri = filter->pri;
    rt_stat_gemFilter_set(filter->index,gemFilter);

    return RT_ERR_OK;
}

static int pf_rt_ResetExtEthPmFilter(UINT16 index)
{    
    rt_stat_gemFilter_conf_t gemFilter;

    memset(&gemFilter,0,sizeof(rt_stat_gemFilter_conf_t));
    gemFilter.enable = DISABLED;
    rt_stat_gemFilter_set(index,gemFilter);
    return RT_ERR_OK;
}

static int pf_rt_GetExtEthPmMib(omci_port_stat_t *pStat)
{
    rt_stat_port_cntr_t cntr;
    memset(&cntr,0,sizeof(rt_stat_port_cntr_t));
    rt_stat_gemFilterMib_get(pStat->port,&cntr);
    pStat->ifInOctets                       = cntr.ifInOctets;
    pStat->ifInUcastPkts                    = cntr.ifInUcastPkts;
    pStat->ifInMulticastPkts                = cntr.ifInMulticastPkts;
    pStat->ifInBroadcastPkts                = cntr.ifInBroadcastPkts;
    pStat->ifInDiscards                     = cntr.ifInDiscards;

    pStat->ifOutOctets                      = cntr.ifOutOctets;
    pStat->ifOutUcastPkts                   = cntr.ifOutUcastPkts;
    pStat->ifOutMulticastPkts               = cntr.ifOutMulticastPkts;
    pStat->ifOutBrocastPkts                 = cntr.ifOutBrocastPkts;
    pStat->ifOutDiscards                    = cntr.ifOutDiscards;

    pStat->dot1dTpPortInDiscards            = cntr.dot1dTpPortInDiscards;
    pStat->dot3StatsSingleCollisionFrames   = cntr.dot3StatsSingleCollisionFrames;
    pStat->dot3StatsMultipleCollisionFrames = cntr.dot3StatsMultipleCollisionFrames;
    pStat->dot3StatsDeferredTransmissions   = cntr.dot3StatsDeferredTransmissions;
    pStat->dot3StatsLateCollisions          = cntr.dot3StatsLateCollisions;
    pStat->dot3InPauseFrames                = cntr.dot3InPauseFrames;
    pStat->dot3OutPauseFrames               = cntr.dot3OutPauseFrames;
    pStat->dot3StatsAligmentErrors          = cntr.dot3StatsAligmentErrors;
    pStat->dot3StatsFCSErrors               = cntr.dot3StatsFCSErrors;
    pStat->dot3StatsSymbolErrors            = cntr.dot3StatsSymbolErrors;
    pStat->dot3StatsFrameTooLongs           = cntr.dot3StatsFrameTooLongs;

    pStat->etherStatsDropEvents             = cntr.etherStatsDropEvents;
    pStat->etherStatsFragments               = cntr.etherStatsFragments;
    pStat->etherStatsJabbers                = cntr.etherStatsJabbers;
    pStat->etherStatsCRCAlignErrors         = cntr.etherStatsCRCAlignErrors;

    pStat->etherStatsTxUndersizePkts        = cntr.etherStatsTxUndersizePkts;
    pStat->etherStatsTxOversizePkts         = cntr.etherStatsTxOversizePkts;
    pStat->etherStatsTxPkts64Octets         = cntr.etherStatsTxPkts64Octets;
    pStat->etherStatsTxPkts65to127Octets    = cntr.etherStatsTxPkts65to127Octets;
    pStat->etherStatsTxPkts128to255Octets   = cntr.etherStatsTxPkts128to255Octets;
    pStat->etherStatsTxPkts256to511Octets   = cntr.etherStatsTxPkts256to511Octets;
    pStat->etherStatsTxPkts512to1023Octets  = cntr.etherStatsTxPkts512to1023Octets;
    pStat->etherStatsTxPkts1024to1518Octets = cntr.etherStatsTxPkts1024to1518Octets;
    pStat->etherStatsTxPkts1519toMaxOctets  = cntr.etherStatsTxPkts1519toMaxOctets;
    pStat->etherStatsTxCRCAlignErrors       = cntr.etherStatsTxCRCAlignErrors;

    pStat->etherStatsRxUndersizePkts        = cntr.etherStatsRxUndersizePkts;
    pStat->etherStatsRxOversizePkts         = cntr.etherStatsRxOversizePkts;
    pStat->etherStatsRxPkts64Octets         = cntr.etherStatsRxPkts64Octets;
    pStat->etherStatsRxPkts65to127Octets    = cntr.etherStatsRxPkts65to127Octets;
    pStat->etherStatsRxPkts128to255Octets   = cntr.etherStatsRxPkts128to255Octets;
    pStat->etherStatsRxPkts256to511Octets   = cntr.etherStatsRxPkts256to511Octets;
    pStat->etherStatsRxPkts512to1023Octets  = cntr.etherStatsRxPkts512to1023Octets;
    pStat->etherStatsRxPkts1024to1518Octets = cntr.etherStatsRxPkts1024to1518Octets;
    pStat->etherStatsRxPkts1519toMaxOctets  = cntr.etherStatsRxPkts1519toMaxOctets;
    return RT_ERR_OK;
}

static int pf_rt_ResetExtEthPmMib(UINT16 index)
{
    rt_stat_gemFilterMib_reset(index);
    return RT_ERR_OK;
}


static int pf_rt_GetXgponPmMib(omci_xgpon_stat_t *pXgponStat)
{
    rt_gpon_pm_counter_t pmCnt;

    if (!pXgponStat)
        return RT_ERR_FAILED;

    memset(&pmCnt,0,sizeof(rt_gpon_pm_counter_t));

    if(XGPON_PM_IS_GET_OMCI(pXgponStat->getBitMap))
    {
        if (RT_ERR_OK != rt_gpon_pmCounter_get(RT_GPON_PM_TYPE_OMCI, (rt_gpon_pm_counter_t *)&pmCnt))
            return RT_ERR_FAILED;
        
        pXgponStat->baselineOmciMsgRecvCnt      = pmCnt.omci.omci_rx_baseline_count;
        pXgponStat->extendedOmciMsgRecvCnt      = pmCnt.omci.omci_rx_extended_count;
        pXgponStat->omciMicErrCnt               = pmCnt.omci.omci_rx_mic_error_count;
    }

    if(XGPON_PM_IS_GET_RX_PLOAM(pXgponStat->getBitMap))
    {      
        if (RT_ERR_OK != rt_gpon_pmCounter_get(RT_GPON_PM_TYPE_PLOAM_PM1, (rt_gpon_pm_counter_t *)&pmCnt))
            return RT_ERR_FAILED;

        pXgponStat->ploamMicErrCnt              = pmCnt.ploam1.ploam_mic_errors;
        pXgponStat->dsPloamMsgCnt               = pmCnt.ploam1.downstream_ploam_message_count;
        pXgponStat->rangingTimeMsgRecv          = pmCnt.ploam1.ranging_time_message_count;

        if (RT_ERR_OK != rt_gpon_pmCounter_get(RT_GPON_PM_TYPE_PLOAM_PM2, (rt_gpon_pm_counter_t *)&pmCnt))
            return RT_ERR_FAILED;  

        pXgponStat->profileMsgRecv              = pmCnt.ploam2.burst_profile_message_count;
        pXgponStat->deactivateOnuIDMsgRecv      = pmCnt.ploam2.deactivate_onu_id_message_count;
        pXgponStat->disableSnMsgRecv            = pmCnt.ploam2.disable_serial_number_message_count;
        pXgponStat->requestReistrationMsgRecv   = pmCnt.ploam2.request_registration_message_count;
        pXgponStat->assignAllocIDMsgRecv        = pmCnt.ploam2.assign_alloc_id_message_count;
        pXgponStat->keyCtrlMsgRecv              = pmCnt.ploam2.key_control_message_count;
        pXgponStat->slpAllowMsgRecv             = pmCnt.ploam2.sleep_allow_message_count;
        pXgponStat->assignOnuIDMsgRecv          = pmCnt.ploam2.assign_onu_id_message_count;
    }

    if(XGPON_PM_IS_GET_TX_PLOAM(pXgponStat->getBitMap))
    {
        if (RT_ERR_OK != rt_gpon_pmCounter_get(RT_GPON_PM_TYPE_PLOAM_PM3, &pmCnt))
            return RT_ERR_FAILED;        

        pXgponStat->usPloamMsgCnt       = pmCnt.ploam3.upstream_ploam_message_count;
        pXgponStat->snOnuMsgCnt         = pmCnt.ploam3.serial_number_onu_in_band_message_count;
        pXgponStat->registrationMsgCnt  = pmCnt.ploam3.registration_message_count;
        pXgponStat->keyReportMsgCnt     = 0;
        pXgponStat->ackMsgCnt           = pmCnt.ploam3.acknowledgement_message_count;
        pXgponStat->slpRequestMsgCnt    = pmCnt.ploam3.sleep_request_message_count;
    }

    if(XGPON_PM_IS_GET_TC(pXgponStat->getBitMap))
    {
        if (RT_ERR_OK != rt_gpon_pmCounter_get(RT_GPON_PM_TYPE_PLOAM_PM3, &pmCnt))
            return RT_ERR_FAILED;        

        pXgponStat->psbdHecErrCnt                   = 0;
        pXgponStat->xgtcHecErrCnt                   = 0;
        pXgponStat->unknownProfileCnt               = 0;
        pXgponStat->transXgponEncMethodXgemFrames   = 0;
        pXgponStat->fragmentXgemFrames              = pmCnt.xgem.transmitted_xgem_frames_with_lf;
        pXgponStat->xgemHecLostWordsCnt             = 0;
        pXgponStat->xgemKeyErrors                   = pmCnt.xgem.xgem_encryption_key_errors;
        pXgponStat->xgemHecErrorCnt                 = pmCnt.xgem.received_xgem_header_hec_errors;
        pXgponStat->transBytesInNonidleXGEMFrames   = 0;
        pXgponStat->LODSEventCnt                    = 0;
        pXgponStat->LODSEventRestoredCnt            = 0;
    }

    return RT_ERR_OK;

}


static int pf_rt_SetSvlanTpid(omci_svlan_tpid_t *p)
{
    if (!p)
        return RT_ERR_FAILED;

    // TBD, Cortina not support setting SVLAN tpid
   
    return RT_ERR_OK;

}

static int pf_rt_GetSvlanTpid(omci_svlan_tpid_t *p)
{
    if (!p)
        return RT_ERR_FAILED;

    // TBD, Cortina not support setting SVLAN tpid

    return RT_ERR_OK;
}

static int pf_rt_GetCvlanState(unsigned int *p)
{
    *p = DISABLED;
    return RT_ERR_OK;
}


static int pf_rt_GetGemBlkLen(unsigned short *pGemBlkLen)
{
    rt_gpon_attribute_t attributeValue;
    memset(&attributeValue,0,sizeof(rt_gpon_attribute_t));
    if(rt_gpon_attribute_get(RT_GPON_ATTRIBUTE_TYPE_GEM_BLOCK_LENGTH,&attributeValue) != RT_ERR_OK)
    {
        *pGemBlkLen = 48;
        return RT_ERR_FAILED;
    }
    *pGemBlkLen = (unsigned short)attributeValue.gemBlockLength;
    return RT_ERR_OK;
}

static int pf_rt_SetGemBlkLen(unsigned short gemBlkLen)
{
    rt_gpon_attribute_t attributeValue;
    memset(&attributeValue,0,sizeof(rt_gpon_attribute_t));
    attributeValue.gemBlockLength = gemBlkLen;
    if(rt_gpon_attribute_set(RT_GPON_ATTRIBUTE_TYPE_GEM_BLOCK_LENGTH,&attributeValue) != RT_ERR_OK)
        return RT_ERR_FAILED;
    return RT_ERR_OK;

}

static int pf_rt_GetDrvVersion(char *drvVersion)
{
#ifdef CONFIG_DRV_RELEASE_VERSION
    snprintf(drvVersion, 64, "%s for RT FC Driver", CONFIG_DRV_RELEASE_VERSION);
#endif
    return RT_ERR_OK;
}

static int pf_rt_GetOnuState(PON_ONU_STATE *pOnuState)
{
    rt_gpon_onuState_t onuState;

    if(!pOnuState)
        return OMCI_ERR_FAILED;
    if(RT_ERR_OK != rt_gpon_onuState_get(&onuState)){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : rt get onu state fail !!",__FUNCTION__,__LINE__);  
    }  

    switch(onuState)
    {
        case RT_GPON_ONU_STATES_O1: //Initial state(O1)
            *pOnuState = PON_ONU_STATE_INITIAL;
            break;
        case RT_GPON_ONU_STATES_O2: //standby state(O2)
            *pOnuState = PON_ONU_STATE_STANDBY;
            break;
        case RT_GPON_ONU_STATES_O3: //Serail number state(O3)
            *pOnuState = PON_ONU_STATE_SERIAL_NUMBER;
            break;
        case RT_GPON_ONU_STATES_O4: //Ranging state(O4)
            *pOnuState = PON_ONU_STATE_RANGING;
            break;
        case RT_GPON_ONU_STATES_O5: //operation state(O5)
            *pOnuState = PON_ONU_STATE_OPERATION;
            break;
        case RT_GPON_ONU_STATES_O6: //Intermittent LODS state(O6)
            *pOnuState = PON_ONU_STATE_POPUP;
            break;
        case RT_GPON_ONU_STATES_O7: //Emergency stop state(O7)
            *pOnuState = PON_ONU_STATE_EMERGENCY_STOP;
            break;
        default:
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : wrong ONU State %d Error!!",__FUNCTION__,__LINE__,onuState);
            return RT_ERR_FAILED;

    }
    
    return OMCI_ERR_OK;
}


static int pf_rt_SetSigParameter(OMCI_SIGNAL_PARA_ts *pSigPara)
{
    rt_gpon_attribute_t attributeValue;

    if (!pSigPara)
        return OMCI_ERR_PARAM;

    if(pSigPara->signal_type == SIG_TYPE_SD)
    {
        memset(&attributeValue,0,sizeof(rt_gpon_attribute_t));
        attributeValue.sdThreshold = pSigPara->signal_threshold;
        if(rt_gpon_attribute_set(RT_GPON_ATTRIBUTE_TYPE_SD_THRESHOLD,&attributeValue) != RT_ERR_OK)
            return OMCI_ERR_FAILED;
    }
    else if(pSigPara->signal_type == SIG_TYPE_SF)
    {
        memset(&attributeValue,0,sizeof(rt_gpon_attribute_t));
        attributeValue.sfThreshold = pSigPara->signal_threshold;
        if(rt_gpon_attribute_set(RT_GPON_ATTRIBUTE_TYPE_SF_THRESHOLD,&attributeValue) != RT_ERR_OK)
            return OMCI_ERR_FAILED;
    }
    else
    {
        return OMCI_ERR_PARAM;
    }
	
    return OMCI_ERR_OK;

}


static int pf_rt_SetPonBwThreshold(omci_pon_bw_threshold_t *pPonBwThreshold)
{
    return RT_ERR_OK;
}

static int pf_rt_DumpVeipGemFlow(void)
{
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    veipGemFlow_entry_t     *pEntryData;
    unsigned int            i;

    list_for_each_safe(pEntry, pTmpEntry, &gPlatformDb.veipGemFlowHead)
    {
        pEntryData = list_entry(pEntry, veipGemFlow_entry_t, list);

        printk(" %10s | %10s | %10s | %10s \n",
            "gemPortId", "tcontId", "flowId", "tcQueueId");

        for (i = 0; i < gDrvCtrl.wanQueueNum; i++)
        {
            printk(" %10u | %10u | %10u | %10u \n",
                pEntryData->data.gemPortId,
                pEntryData->data.tcontId,
                pEntryData->data.flowId[i],
                pEntryData->data.tcQueueId[i]);
        }

        printk("################################################\n");
    }

    return OMCI_ERR_OK;
}

static int pf_rt_SetVeipGemFlow(veipGemFlow_t *p)
{
    veipGemFlow_entry_t     *pEntry;

    if (!p)
        return RT_ERR_FAILED;

    pEntry = veipGemFlow_entry_find(p->gemPortId);
    if (pEntry)
        memcpy(&pEntry->data, p, sizeof(veipGemFlow_t));
    else
    {
        if (OMCI_ERR_OK != veipGemFlow_entry_add(p))
            return RT_ERR_FAILED;
    }

    return RT_ERR_OK;
}

static int pf_rt_DelVeipGemFlow(veipGemFlow_t *p)
{
    veipGemFlow_entry_t     *pEntry;

    if (!p)
        return RT_ERR_FAILED;

    pEntry = veipGemFlow_entry_find(p->gemPortId);
    if (!pEntry)
        return RT_ERR_FAILED;

    if (OMCI_ERR_OK != veipGemFlow_entry_del(p->gemPortId))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_SetUniPortRate(omci_port_rate_t *p)
{
    if (!p)
        return RT_ERR_FAILED;

    if (OMCI_UNI_RATE_DIRECTION_EGRESS == p->dir)
    {
        if (RT_ERR_OK != rt_rate_portEgrBandwidthCtrlRate_set(p->port, p->rate))
            return RT_ERR_FAILED;
    }
    else
    {
        if (RT_ERR_OK != rt_rate_portIgrBandwidthCtrlRate_set(p->port, p->rate))
            return RT_ERR_FAILED;
    }
    return RT_ERR_OK;
}

static int pf_rt_SetPauseControl(omci_port_pause_ctrl_t *p)
{
    rt_port_phy_ability_t  phyAbility;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyAutoNegoAbility_get(p->port, &phyAbility))
        return RT_ERR_FAILED;

           
    /*Only support enable / disable flow control*/
    if(0 == p->pause_time)
    {
        if(0 == phyAbility.FC && 0 ==phyAbility.AsyFC)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s due to same config, skip disable FC for port[%u]", __FUNCTION__, p->port);
            return RT_ERR_OK;            
        }
        phyAbility.FC = 0;
        phyAbility.AsyFC = 0;
    }
    else
    {
        if(1 == phyAbility.FC && 1 ==phyAbility.AsyFC)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s due to same config, skip enable FC port[%u]", __FUNCTION__,  p->port);
            return RT_ERR_OK;            
        }
        phyAbility.FC = 1;
        phyAbility.AsyFC = 1;
    }

    if (RT_ERR_OK != rt_port_phyAutoNegoAbility_set(p->port, &phyAbility))
        return RT_ERR_FAILED;

    return RT_ERR_OK;
}

static int pf_rt_GetPauseControl(omci_port_pause_ctrl_t *p)
{
    rt_port_phy_ability_t  phyAbility;

    if (!p)
        return RT_ERR_FAILED;

    if (RT_ERR_OK != rt_port_phyAutoNegoAbility_get(p->port, &phyAbility))
        return RT_ERR_FAILED;

    p->pause_time = phyAbility.FC;

    return RT_ERR_OK;
}

static int pf_rt_SetDsBcGemFlow(unsigned int *pFlowId)
{
    return RT_ERR_OK;
}

static int pf_rt_SetDot1RateLimiter(omci_dot1_rate_meter_t *pDot1RateMeter)
{
// TBD
    return RT_ERR_OK;

}

static int pf_rt_DelDot1RateLimiter(omci_dot1_rate_meter_t *pDot1RateMeter)
{
    /*TBD*/
    return RT_ERR_OK;
}

static int pf_rt_GetBridgeTblPerPort(omci_bridge_tbl_per_port_t *p)
{
    rt_l2_ucastAddr_t   l2table;
    uint32              index = 0, scanIdx;
    unsigned char       information[2],is_dynamic,is_filter;
    unsigned char       *pPos = NULL;


    if (!p)
        return RT_ERR_INPUT;

    OMCI_LOG(OMCI_LOG_LEVEL_DBG,
                        "%s() portId=%u\n", __FUNCTION__,
                        p->portId);

    memset(gPlatformDb.pMmap, 0, MMT_BUF_SIZE);
    pPos = gPlatformDb.pMmap;

    scanIdx = index; //init
    do
    {
        memset(&l2table, 0x0, sizeof(rt_l2_ucastAddr_t));
        index = scanIdx;

        if(RT_ERR_OK == (rt_l2_nextValidAddrOnPort_get(p->portId, &scanIdx,&l2table)))
        {

            OMCI_LOG(OMCI_LOG_LEVEL_DBG,
                                "%s() %d\n",
                                __FUNCTION__, __LINE__);
            /* Wrap around */
            if(scanIdx < index)
            {
                break;
            }

            is_dynamic = (l2table.staticFlag == ENABLED ? 0 : 1);
            is_filter = (l2table.filterFlag == ENABLED ? 1 : 0);
            information[0] = (l2table.age & 0xFF0) >> 4;
            information[1] = ((l2table.age & 0xF) << 4) | ((is_dynamic & 0x1) << 2) | (is_filter & 0x1);
            memcpy(pPos, &information, sizeof(information));
            pPos += sizeof(information);
            memcpy(pPos, l2table.mac.octet, ETHER_ADDR_LEN);
            pPos += ETHER_ADDR_LEN;
            p->cnt++;
            OMCI_LOG(OMCI_LOG_LEVEL_INFO,
                    "l2 entry learn count=%u, age=%u, is_dynamic=%u, is_filter=%u, mac=%02x:%02x:%02x:%02x:%02x:%02x,information=0x%x %x\n",
                    p->cnt, l2table.age, is_dynamic, is_filter,
                    l2table.mac.octet[0],
                    l2table.mac.octet[1],
                    l2table.mac.octet[2],
                    l2table.mac.octet[3],
                    l2table.mac.octet[4],
                    l2table.mac.octet[5],
                    information[0],information[1]);
        }
        else
        {
            OMCI_LOG(OMCI_LOG_LEVEL_DBG,
                                "%s() %d, scanIdx=%d\n",
                                __FUNCTION__, __LINE__, scanIdx);
            if (scanIdx > gPlatformDb.maxLearnCnt)
                break;
        }
        scanIdx++;
    } while(1);

    return RT_ERR_OK;

}


static int pf_rt_SetMacAgeTime(unsigned int ageTime)
{
    /*TBD*/
//    rt_l2_aging_set(ageTime * 1000);
    return RT_ERR_OK;
}


static int pf_rt_SetLoidAuthStatus(omci_event_msg_t *p)
{
    uint8 authStatus = p->status;

    if((authStatus != PON_ONU_LOID_INITIAL_STATE) && (authStatus != PON_ONU_LOID_SUCCESSFUL_AUTHENTICATION))
    {
        rtk_pon_led_status_set(PON_LED_PON_MODE_GPON, PON_LED_STATE_AUTH_NG);
    }
    else if(authStatus == PON_ONU_LOID_SUCCESSFUL_AUTHENTICATION)
    {
        rtk_pon_led_status_set(PON_LED_PON_MODE_GPON, PON_LED_STATE_AUTH_OK);

        queue_broadcast(MSG_TYPE_OMCI_EVENT, p->subType, p->bitMask, p->status);
    }

    return RT_ERR_OK;
}

static int pf_rt_SendOmciEvent(omci_event_msg_t *p)
{
    queue_broadcast(MSG_TYPE_OMCI_EVENT,
        p->subType, p->bitMask, p->status);

    return RT_ERR_OK;
}

static int pf_rt_SetForceEmergencyStop(unsigned int *pState)
{
    return RT_ERR_OK;
}

static int pf_rt_SetTodInfo ( omci_tod_info_t* pTodInfo)
{
    int32 ret = RT_ERR_FAILED;
    rt_enable_t enable = DISABLED;
    rt_pon_tod_t ponTod;
    unsigned long long uTimeStampSecs;

    if (!pTodInfo) {
        return (RT_ERR_INPUT);
    }

    memset (&ponTod, 0x00, sizeof (rt_pon_tod_t));

    /* Avoid compiler warning when printing */
    uTimeStampSecs = pTodInfo->uTimeStampSecs;

    OMCI_LOG(OMCI_LOG_LEVEL_DBG,
        "%s: superframe 0x%x, sec %llu, ns %u\n",
        __FUNCTION__,
        pTodInfo->uSeqNumOfGemSuperframe,
        uTimeStampSecs,
        pTodInfo->uTimeStampNanosecs);

    ponTod.ponMode = TOD_PON_MODE_GPON;
    ponTod.startPoint.superFrame = pTodInfo->uSeqNumOfGemSuperframe;
    ponTod.timeStamp.sec         = pTodInfo->uTimeStampSecs;
    ponTod.timeStamp.nsec         = pTodInfo->uTimeStampNanosecs;
    enable = ENABLED;

    ret = rt_time_ponTodTime_set(ponTod);
    if (ret != RT_ERR_OK) {
        OMCI_LOG(OMCI_LOG_LEVEL_DBG,
            "Failed to set time of ToD, ret %d", ret);
        return ret;
    }

    ret = rt_time_ponTodTimeEnable_set(enable);
    if (ret != RT_ERR_OK) {
        OMCI_LOG(OMCI_LOG_LEVEL_DBG,
            "Failed to enable ToD, ret %d", ret);
    }

    return ret;
}


static void gpon_state_change(intrBcasterMsg_t *pMsgData)
{
    int ret = OMCI_ERR_OK;

    if (MSG_TYPE_ONU_STATE == pMsgData->intrType &&
        gPlatformDb.ponPort ==  pMsgData->intrBitMask)
    {
        ret = rtk_pon_led_status_set(PON_LED_PON_MODE_GPON, (uint32)pMsgData->intrSubType);
        if(RT_ERR_OK != ret)
            OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d set LED fail ret:%d",__FUNCTION__,__LINE__,ret);

        
    }

    return;
}
static int pf_rt_DumpDebugInfo(void)
{
    _DumpTcontCfg(gPlatformDb.maxTcont);
    _DumpUsGemFlowCfg(gPlatformDb.maxFlow);
    _DumpDsGemFlowCfg(gPlatformDb.maxFlow);
    _DumpTcontQueueCfg(gPlatformDb.maxTcont, gPlatformDb.maxTcontQueue);

    omci_qos_flow_dump(gPlatformDb.maxFlow);
		
    return OMCI_ERR_OK;
}


static int pf_rt_DumpFlow2dsPq(void)
{
    struct list_head        *pEntry;
    struct list_head        *pTmpEntry;
    flow2DsPq_entry_t       *pEntryData;

    printk("---------------------------------------------------------------------------------------------\n");

    printk(" %10s | %10s | %10s | %10s | %10s | %10s | %10s\n",
        "flowId", "dsPqOmciPri", "dpMarking", "lanPort", "policy", "priority", "weight");
    printk("---------------------------------------------------------------------------------------------\n");
    list_for_each_safe(pEntry, pTmpEntry, &gPlatformDb.flow2DsPqHead)
    {
        pEntryData = list_entry(pEntry, flow2DsPq_entry_t, list);

        printk(" %10u | %10u | %10u | %10u | %10u | %10u | %10u\n",
            pEntryData->flowId,
            pEntryData->dsQ.dsPqOmciPri,
            pEntryData->dsQ.dpMarking,
            pEntryData->dsQ.portId,
            pEntryData->dsQ.policy,
            pEntryData->dsQ.priority,
            pEntryData->dsQ.weight);

        printk("---------------------------------------------------------------------------------------------\n");
    }

    return OMCI_ERR_OK;
}

static int pf_rt_SetOmciMirror(unsigned int *p)
{
    int ret = OMCI_ERR_OK;

    if (!p)
        return RT_ERR_FAILED;

    if(*p == 0xFFFFFFFF)/*disable*/
    {
        ret = rt_gpon_omci_mirror_set(0,0);
    }
    else
    {
        ret = rt_gpon_omci_mirror_set(1,*p);
    }

    return ret;
}






static pf_wrapper_t rt_fc_mapper =
{
    //Link related
    .pf_ResetMib                    = pf_rt_ResetMib,
    .pf_GetSerialNum                = pf_rt_GetSerialNum,
    .pf_SetSerialNum                = pf_rt_SetSerialNum,
    .pf_SetGponPasswd               = pf_rt_SetGponPasswd,
    .pf_ActivateGpon                = pf_rt_ActivateGpon,
    .pf_GetPonSpeed                 = pf_rt_GetPonSpeed,

    //ANI setting
    .pf_ClearPriQueue               = pf_rt_ClearPriQueue,
    .pf_SetPriQueue                 = pf_rt_SetPriQueue,
    .pf_CfgGemFlow                  = pf_rt_CfgGemFlow,
    .pf_CfgGemRate                  = pf_rt_CfgGemRate,
    .pf_CreateTcont                 = pf_rt_CreateTcont,
    .pf_UpdateTcont                 = pf_rt_UpdateTcont,

    //Connection
    .pf_ActiveBdgConn               = pf_rt_ActiveBdgConn,
    .pf_DeactiveBdgConn             = pf_rt_DeactiveBdgConn,

    .pf_SetCfMap                    = NULL,
    .pf_SetDscpRemap                = pf_rt_SetDscpRemap,

    .pf_UpdateVeipRule              = NULL,
    .pf_SetMacLearnLimit            = pf_rt_SetMacLearnLimit,
    .pf_SetMacFilter                = pf_rt_SetMacFilter,
    .pf_GetDevCapabilities          = pf_rt_GetDevCapabilities,
    .pf_GetDevIdVersion             = pf_rt_GetDevIdVersion,
    .pf_GetUsDBRuStatus             = pf_rt_GetUsDBRuStatus,
    .pf_GetOnuRspTime               = pf_rt_GetOnuRspTime,
    .pf_GetTransceiverStatus        = pf_rt_GetTransceiverStatus,
    .pf_GetPortLinkStatus           = pf_rt_GetPortLinkStatus,
    .pf_GetPortSpeedDuplexStatus    = pf_rt_GetPortSpeedDuplexStatus,
    .pf_SetPortAutoNegoAbility      = pf_rt_SetPortAutoNegoAbility,
    .pf_GetPortAutoNegoAbility      = pf_rt_GetPortAutoNegoAbility,
    .pf_SetPortState                = pf_rt_SetPortState,
    .pf_GetPortState                = pf_rt_GetPortState,
    .pf_SetPortMaxFrameSize         = pf_rt_SetPortMaxFrameSize,
    .pf_GetPortMaxFrameSize         = pf_rt_GetPortMaxFrameSize,
    .pf_SetPortPhyLoopback          = pf_rt_SetPortPhyLoopback,
    .pf_GetPortPhyLoopback          = pf_rt_GetPortPhyLoopback,
    .pf_SetPortPhyPwrDown           = pf_rt_SetPortPhyPwrDown,
    .pf_GetPortPhyPwrDown           = pf_rt_GetPortPhyPwrDown,

    //Statistics
    .pf_GetPortStat                 = pf_rt_GetPortStat,
    .pf_ResetPortStat               = pf_rt_ResetPortStat,
    .pf_GetUsFlowStat               = pf_rt_GetUsFlowStat,
    .pf_ResetUsFlowStat             = pf_rt_ResetUsFlowStat,
    .pf_GetDsFlowStat               = pf_rt_GetDsFlowStat,
    .pf_ResetDsFlowStat             = pf_rt_ResetDsFlowStat,
    .pf_GetDsFecStat                = pf_rt_GetDsFecStat,
    .pf_ResetDsFecStat              = pf_rt_ResetDsFecStat,

    .pf_SetExtEthPmFilter           = pf_rt_SetExtEthPmFilter,
    .pf_ResetExtEthPmFilter         = pf_rt_ResetExtEthPmFilter,
    .pf_GetExtEthPmMib              = pf_rt_GetExtEthPmMib,
    .pf_ResetExtEthPmMib            = pf_rt_ResetExtEthPmMib,
    .pf_GetXgponStat                = pf_rt_GetXgponPmMib,

    //TBD, sync linux kernel protocol stack
    .pf_SetSvlanTpid                = pf_rt_SetSvlanTpid,
    .pf_GetSvlanTpid                = pf_rt_GetSvlanTpid,
    .pf_GetCvlanState               = pf_rt_GetCvlanState,
    .pf_GetGemBlkLen                = pf_rt_GetGemBlkLen,
    .pf_SetGemBlkLen                = pf_rt_SetGemBlkLen,
    .pf_SetGroupMacFilter           = NULL,
    .pf_GetDrvVersion               = pf_rt_GetDrvVersion,
    .pf_GetOnuState                 = pf_rt_GetOnuState,
    .pf_SetSigParameter             = pf_rt_SetSigParameter,
    .pf_SetPonBwThreshold           = pf_rt_SetPonBwThreshold,
    .pf_DumpVeipGemFlow             = pf_rt_DumpVeipGemFlow,
    .pf_SetVeipGemFlow              = pf_rt_SetVeipGemFlow,
    .pf_DelVeipGemFlow              = pf_rt_DelVeipGemFlow,
    .pf_SetUniPortRate              = pf_rt_SetUniPortRate,
    .pf_SetPauseControl             = pf_rt_SetPauseControl,
    .pf_GetPauseControl             = pf_rt_GetPauseControl,
    .pf_SetDsBcGemFlow              = pf_rt_SetDsBcGemFlow,
    //TBD, sync linux kernel protocol stack
    .pf_SetDot1RateLimiter          = pf_rt_SetDot1RateLimiter,
    .pf_DelDot1RateLimiter          = pf_rt_DelDot1RateLimiter,
    .pf_GetBgTblPerPort             = pf_rt_GetBridgeTblPerPort,
    .pf_SetMacAgeTime               = pf_rt_SetMacAgeTime,
    .pf_SetLoidAuthStatus           = pf_rt_SetLoidAuthStatus,
    .pf_SendOmciEvent               = pf_rt_SendOmciEvent,
    .pf_SetForceEmergencyStop       = pf_rt_SetForceEmergencyStop,
    .pf_SetPortBridging             = NULL,
    .pf_SetFloodingPortMask         = NULL,
    .pf_SetTodInfo                  = pf_rt_SetTodInfo,
    .pf_SetUniQosInfo               = NULL,

    //10G only
    .pf_SetMSK                      = pf_rt_SetMSK,
    .pf_GetPonTag                   = pf_rt_getPonTag,
    .pf_SetOmciIk                   = pf_rt_SetOmciIk,
    .pf_SetMcKey                    = pf_rt_SetMcKey,

    //Debug 
    .pf_DumpDebugInfo               = pf_rt_DumpDebugInfo,
    .pf_DumpL2Serv                  = pf_rt_DumpL2Serv,
    .pf_DumpVeipServ                = pf_rt_DumpVeipServ,
    .pf_DumpMBServ                  = pf_rt_DumpMBServ,
    .pf_DumpCfMap                   = NULL,
    .pf_DumpMacFilter               = NULL,
    .pf_DumpFlow2dsPq               = pf_rt_DumpFlow2dsPq,
    .pf_SetOmciMirror               = pf_rt_SetOmciMirror,

    .pf_SetOmciDyingGaspMsg         = pf_rt_SetOmciDyingGaspMsg,

};

static intrBcasterNotifier_t gponStateChangeNotifier = {
    .notifyType = MSG_TYPE_ONU_STATE,
    .notifierCb = gpon_state_change,
};


static int platform_db_init(void)
{
    rt_switch_devInfo_t        devInfo;
    rt_register_capacity_t      *pCapacityInfo;
    rt_gpon_schedule_info_t     scheInfo;
    int                         i;
    unsigned int                utpPortNum = 0;
    unsigned int                wifi_ext_port_max_num = 0, wifi_ext_port_cnt = 0;
    int                         ret = RT_ERR_OK;
    unsigned int                portMask;
    rt_portmask_t               ether_pmk;

    memset(&gPlatformDb, 0, sizeof(pf_db_t));
    INIT_LIST_HEAD(&gPlatformDb.l2Head);
    INIT_LIST_HEAD(&gPlatformDb.veipHead);
    INIT_LIST_HEAD(&gPlatformDb.veipGemFlowHead);
    INIT_LIST_HEAD(&gPlatformDb.mbcastHead);
    INIT_LIST_HEAD(&gPlatformDb.macFilterHead);
    INIT_LIST_HEAD(&gPlatformDb.flow2DsPqHead);
    INIT_LIST_HEAD(&gPlatformDb.dpStagAclHead);
    INIT_LIST_HEAD(&gPlatformDb.dsDpGemStagAclHead);
    
    INIT_LIST_HEAD(&gL2FlowHead);
    INIT_LIST_HEAD(&gVeipFlowHead);
    INIT_LIST_HEAD(&gL2DsDftHead);
    INIT_LIST_HEAD(&gVeipDsDftHead);

    ret = rt_switch_deviceInfo_get(&devInfo);     
    if (RT_ERR_OK != ret){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : init fail ret:%d", __FUNCTION__, __LINE__, ret);
        return OMCI_ERR_FAILED;
    }
    pCapacityInfo = &devInfo.capacityInfo;

    // chip info
    gPlatformDb.chipId = devInfo.chipId;

    ret = rt_gpon_init(); 
    if (RT_ERR_OK != ret){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : init fail ret:%d", __FUNCTION__, __LINE__, ret);
        return OMCI_ERR_FAILED;
    }

    ret = rt_gpon_scheInfo_get(&scheInfo); 
    if (RT_ERR_OK != ret){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : init fail ret:%d", __FUNCTION__, __LINE__, ret);
        return OMCI_ERR_FAILED;
    }


    gPlatformDb.maxTcont        = scheInfo.max_tcont;
    gPlatformDb.maxTcontQueue   = scheInfo.max_tcon_queue;
    gPlatformDb.maxPonQueue     = scheInfo.max_pon_queue;
    gPlatformDb.maxFlow         = scheInfo.max_flow;


    gPlatformDb.tCont = kmalloc(sizeof(pf_tcont_t) * gPlatformDb.maxTcont, GFP_KERNEL);
    if (!gPlatformDb.tCont){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : init fail",__FUNCTION__,__LINE__);
        return OMCI_ERR_FAILED;
    }

    _InitTcontDb();

    ret = omci_qos_flow_init(gPlatformDb.maxFlow);
    if(ret != OMCI_ERR_OK)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : qos flow init fail",__FUNCTION__,__LINE__);
        return OMCI_ERR_FAILED;
    }




    // port info
    gPlatformDb.cpuPort = devInfo.cpuPort;
    gPlatformDb.rgmiiPort = devInfo.rgmiiPort;
    gPlatformDb.ponPort = devInfo.ponPort;  

    RTK_PORTMASK_RESET(ether_pmk);
    HAL_GET_ETHER_PORTMASK(ether_pmk); /* include pon portmask  */
    portMask = ether_pmk.bits[0];
    gPlatformDb.etherPortMin = devInfo.ether.min;
    gPlatformDb.etherPortMax = devInfo.ether.max;
    for (i = gPlatformDb.etherPortMin; i <= gPlatformDb.etherPortMax; i++)
    {
        if (i == gPlatformDb.cpuPort ||
                i == gPlatformDb.rgmiiPort ||
                i == gPlatformDb.ponPort)
            continue;

        if(0 != (portMask & (1 << i))) //avoid non-continuous port mask
        {
            gPlatformDb.etherPortMask |= (1 << i);
            utpPortNum++;
        }
    }

    if(0 == utpPortNum)/*Check UTP number*/
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : init fail",__FUNCTION__,__LINE__);
        return OMCI_ERR_FAILED;
    }
    
    gPlatformDb.allPortMin = devInfo.all.min;
    gPlatformDb.allPortMax = devInfo.all.max;
    for (i = gPlatformDb.allPortMin; i <= gPlatformDb.allPortMax; i++)
    {
        if (!((1 << i) & gPlatformDb.etherPortMask))
            continue;

        gPlatformDb.uniPortMask |= (1 << i);
    }
    gPlatformDb.uniPortMask |= (1 << gPlatformDb.cpuPort);
    gPlatformDb.perUniQueue = pCapacityInfo->max_num_of_queue;
    if (devInfo.ext.portNum > 0)
    {
        wifi_ext_port_max_num = 2;
        for (i = devInfo.ext.min; i <= devInfo.ext.max; i++)
        {
            if (wifi_ext_port_max_num <= wifi_ext_port_cnt)
                break;

            if (RTL9607C_CHIP_ID == gPlatformDb.chipId)
            {
                // plus 2 for offset MAC10 and EXT_CPU
                gPlatformDb.extPortMask |= (1 << (i + gPlatformDb.cpuPort + 2));
            }
            else
            {
                // plus 1 for offset EXT_CPU
                gPlatformDb.extPortMask |= (1 << (i + gPlatformDb.cpuPort + 1));
            }
            wifi_ext_port_cnt++;
        }
    }
    // qos
//    gPlatformDb.maxPriSelWeight = pCapacityInfo->pri_sel_weight_max;
    gPlatformDb.perTContQueueDp = FALSE;
    gPlatformDb.perUNIQueueDp = FALSE;
    gPlatformDb.rsvMeterId = ((gPlatformDb.cpuPort % utpPortNum) * 8 + 7);
    gPlatformDb.meterNum = pCapacityInfo->max_num_of_metering;
    gPlatformDb.stormCtrl = kzalloc(sizeof(pf_stormCtrl_t) * gPlatformDb.meterNum, GFP_KERNEL);
    if (!gPlatformDb.stormCtrl){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s %d : init fail",__FUNCTION__,__LINE__);
        return OMCI_ERR_FAILED;
    }



    // acl
    gPlatformDb.aclNum = pCapacityInfo->max_num_of_acl_rule_entry;
    gPlatformDb.aclActNum = pCapacityInfo->max_num_of_acl_action;

    // BW rate
 
 
    ret = rt_rate_portIgrBandwidthCtrlRate_get(gPlatformDb.ponPort, &gPlatformDb.maxBwRate); 
    if (RT_ERR_OK != ret){
        OMCI_LOG(OMCI_LOG_LEVEL_ERR,"%s() %d : init fail ret:%d", __FUNCTION__, __LINE__, ret);
        return OMCI_ERR_FAILED;
    }



    // l34, intfNum follows sw table size. No mater which chip, SW will handle it if the number of netif is larger than hardware limitation
    //gPlatformDb.intfNum = pCapacityInfo->l34_netif_table_max;
    //gPlatformDb.bindingTblMax = pCapacityInfo->l34_binding_table_max;
    // callback
    gPlatformDb.pMap = &rt_fc_mapper;



    printk("omci platform db suc!\n"); 
    printk("ponPort:%d cpuPort:%d rgmiiPort:%d uniPortMask:0x%x  etherPortMask:0x%x\n",
        gPlatformDb.ponPort,
        gPlatformDb.cpuPort,
        gPlatformDb.rgmiiPort,
        gPlatformDb.uniPortMask,
        gPlatformDb.etherPortMask);
    
    return OMCI_ERR_OK;
}

void omci_dmm_cb_register(omci_dmm_cb_t *p)
{
    pDmmCb = p;
}


void omci_dmm_cb_unregister(void)
{
    pDmmCb = NULL;
}


/*EXPORT function*/
EXPORT_SYMBOL(omci_dmm_cb_register);
EXPORT_SYMBOL(omci_dmm_cb_unregister);


int __init rtk_platform_init(void)
{

    platform_db_init();

    omcidrv_platform_register(&gPlatformDb);
    printk("omci platform attached!\n");


    if(OMCI_ERR_OK != omci_init())
        return OMCI_ERR_OK;


    if(OMCI_ERR_OK != intr_bcaster_notifier_cb_register(&gponStateChangeNotifier))
    {
        printk("OMCI register bcaster notifier chain Error !! \n");
    }

    return OMCI_ERR_OK;
}

void __exit rtk_platform_exit(void)
{

    if(OMCI_ERR_OK != intr_bcaster_notifier_cb_unregister(&gponStateChangeNotifier))
    {
        printk("OMCI unregister bcaster notifier chain Error !! \n");
    }

    pf_rt_ExitPlatform();
}


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RealTek OMCI kernel module");
MODULE_AUTHOR("RealTek");

module_init(rtk_platform_init);
module_exit(rtk_platform_exit);
